2011-11-18 17 views
5

Tengo una aplicación Java EE ejecutándose en Glassfish y conectándose a MSSQL Server 2008 mediante jTDS. Por alguna razón desconocida, la conexión de la base de datos se cierra inesperadamente durante las solicitudes. La aplicación es enorme, pero aquí hay un resumen de cómo ocurre el error:Conexión de la base de datos cerrada inesperadamente con Glassfish, jTDS y SQL Server 2008

Durante la instalación de Glassfish, con crear un grupo de conexión con asadmin create-jdbc-connection-pool y asadmin create-jdbc-resource. La clase de fuente de datos es net.sourceforge.jtds.jdbcx.JtdsDataSource.

Cuando Glassfish sube, llama a nuestra implementación de ServletContextListener.contextInitialized(), donde buscamos el origen de datos de JNDI. El origen de datos se almacena en una variable estática.

Por un tiempo, todo va bien. Todas las solicitudes se manejan y no se cierra ninguna conexión. Nuestra aplicación realiza el procesamiento utilizando EJBs de temporizador y MDB (Bean controlado por mensajes).

Este es un ejemplo de implementación onMessage():

public void onMessage(Message message) { 
    this.message = message; 
    this.connection = dataSource.getConnection(userName, password); 
    try { 
    doQuery1(); 
    doTransaction1(); 
    doTransaction2(); 
    doQuery2(); 
    doQuery3(); 
    } finally { 
    this.connection.close(); 
    this.connection = null; 
    } 
} 

Con el tiempo, empezamos a obtener la siguiente excepción (que sucede alrededor de 100 veces durante una hora):

java.sql.SQLException: Invalid state, the Connection object is closed. 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.checkOpen(ConnectionJDBC2.java) 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java) 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java) 
    at com.sun.gjc.spi.base.ConnectionHolder.prepareStatement(ConnectionHolder.java:475) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:123) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011) 
    ... 
    at $Proxy92.onMessage(Unknown Source) 
    at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java) 
    at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77) 
    at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555) 

La excepción ocurre en JDBC al azar llamadas. A veces ocurre durante la iteración ResultSet, otras veces durante la ejecución de la consulta.

En casos muy raros (7 veces durante una hora) obtenemos esta excepción:

java.sql.SQLException: Error in allocating a connection. Cause: This Managed Connection is not valid as the phyiscal connection is not usable 
    at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:136) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011) 
    ... 
    at $Proxy92.onMessage(Unknown Source) 
    at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java) 
    at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77) 
    at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555) 

También en casos muy raros (5 veces durante una hora) obtenemos esta excepción:

java.sql.SQLException: I/O Error: Connection reset by peer: socket write error 
    at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java) 
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java) 
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    ... 
Caused by: java.net.SocketException: Connection reset by peer: socket write error 
    at java.net.SocketOutputStream.socketWrite0(Native Method) 
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java) 
    at java.net.SocketOutputStream.write(SocketOutputStream.java) 
    at java.io.DataOutputStream.write(DataOutputStream.java) 
    at net.sourceforge.jtds.jdbc.SharedSocket.sendNetPacket(SharedSocket.java) 
    at net.sourceforge.jtds.jdbc.RequestStream.putPacket(RequestStream.java) 
    at net.sourceforge.jtds.jdbc.RequestStream.flush(RequestStream.java) 
    ... 44 more 

En casos raros obtenemos esta excepción miedo (NPE dentro jTDS):

java.lang.NullPointerException 
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    ... 

no podemos encontrar por qué sucede esto. Las conexiones utilizadas nunca permanecen inactivas durante más de un segundo durante una solicitud. No sabemos quién está abandonando la conexión. Puede ser inestabilidad de la red, pero supongo que jTDS solo debe producir excepciones relacionadas con la red, ¿verdad?

Otra opción es alguna política o configuración del grupo de conexiones de Glassfish (tal vez Glassfish está cerrando conexiones físicas prematuramente), pero ¿cómo podemos rastrearlo?

Finalmente, MS SQL Server 2008 puede estar desconectando conexiones de forma remota, pero ¿cómo podemos controlar el lado del servidor para saber si está sucediendo?

+0

cuando se utiliza el controlador JDBC de Microsoft de? – extraneon

+0

@extraneon No probamos el controlador Microsoft JDBC. Existe una capa de persistencia completa basada en jTDS y el cambio a MS llevaría algunos días. – fernacolo

+0

¿Su código captura/ignora las SQLExcepciones? ¿Estás usando un DataSource básico o un grupo de conexión? –

Respuesta

2

Tenía una aplicación que recibía este tipo de excepciones casi exactamente. Todas mis máquinas eran nuevos servidores y todas las tarjetas de red estaban configuradas para detectar automáticamente la velocidad de la red. Todos estaban conectados a un viejo interruptor que era 100MB/second HALF dúplex.

Configurar todas las máquinas en ese conmutador para usar explícitamente la configuración de conexión dúplex HALF de 100MB/segundo en lugar de autodetección fue lo que funcionó para mí después de hacer innumerables horas buscando una solución. Tendrá que averiguar cuáles deberían ser sus configuraciones de conectividad o experimentar (será obvio si elige la incorrecta porque no podrá conectarse a la caja en el escritorio remoto, así que asegúrese de poder acceder al máquina física).

Es bastante baja la fruta que cuelga para probar esto. Configuré una ventana de comando con un comando ping desde una de las máquinas de trabajo que hace ping al servidor de la base de datos y pude ver la pérdida de paquetes periódicamente. Una vez que cambié la configuración de NIC y lo hice bien, el problema desapareció por completo. Hay varios artículos en Internet que discuten este problema. Es difícil de rastrear porque es: 1) periódico y 2) parece que algo está mal con los objetos de conexión, etc.

Cuestiones relacionadas