2011-11-18 1 views
5

Possiedo un'applicazione Java EE in esecuzione su Glassfish e connessione a MSSQL Server 2008 tramite jTDS. Per qualche motivo sconosciuto, la connessione al database si chiude inaspettatamente durante le richieste. L'applicazione è enorme, ma qui è un riepilogo di come si verifica l'errore:Connessione al database chiusa in modo imprevisto con Glassfish, jTDS e SQL Server 2008

Durante la configurazione Glassfish, con creare un pool di connessione con asadmin create-jdbc-connection-pool e asadmin create-jdbc-resource. La classe dell'origine dati è net.sourceforge.jtds.jdbcx.JtdsDataSource.

Quando Glassfish sale, chiama la nostra implementazione di ServletContextListener.contextInitialized(), dove recuperiamo l'origine dati da JNDI. L'origine dati è memorizzata su una variabile statica.

Per un po ', tutto va bene. Tutte le richieste vengono gestite e nessuna connessione viene chiusa. La nostra applicazione esegue l'elaborazione utilizzando gli EJB di Timer e MDB (Message Driven Bean).

Questo è un esempio di implementazione 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; 
    } 
} 

Eventualmente, si inizia a ottenere la seguente eccezione (accade circa 100 volte durante un'ora):

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) 

L'eccezione avviene a JDBC casuale chiamate. A volte è durante l'iterazione ResultSet, altre volte durante l'esecuzione della query.

In casi molto rari (7 volte durante un'ora) otteniamo questa eccezione:

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) 

Anche in casi molto rari (5 volte nel corso di un ora) si ottiene questa eccezione:

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 

In rari casi si ottiene questa eccezione spaventoso (NPE all'interno 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) 
    ... 

non possiamo trovare il motivo per cui questo accade. Le connessioni utilizzate non diventano mai inattive per più di un secondo durante una richiesta. Non sappiamo chi sta lasciando cadere la connessione. Potrebbe essere l'instabilità della rete, ma suppongo che jTDS dovrebbe produrre solo eccezioni relative alla rete, giusto?

Un'altra opzione è una politica o configurazione del pool di connessione Glassfish (forse Glassfish sta chiudendo le connessioni fisiche prematuramente), ma come possiamo seguirlo?

Infine, MS SQL Server 2008 può disconnettere da remoto le connessioni, ma come possiamo monitorare il lato server per sapere se sta accadendo?

+0

si verificano anche i problemi quando si utilizza il driver JDBC Microsofts? – extraneon

+0

@extraneon Non abbiamo testato il driver Microsoft JDBC. C'è un intero livello di persistenza basato su jTDS e il passaggio a MS richiederebbe alcuni giorni per realizzarlo. – fernacolo

+0

Il codice cattura/ignora SQLExceptions? Stai usando un DataSource di base o un connectionpool? –

risposta

2

Avevo un'applicazione che ha ricevuto questo tipo di eccezioni quasi esattamente. Tutte le mie macchine erano server nuovi di zecca e tutte le schede di rete erano impostate per rilevare automaticamente la velocità della rete. Erano tutti collegati a un vecchio interruttore che era 100MB/secondo HALF duplex.

Impostazione di tutte le macchine su quello switch per utilizzare in modo esplicito l'impostazione della connessione duplex HALF a 100 MB/secondo piuttosto che il rilevamento automatico è stato ciò che ha funzionato per me dopo aver fatto innumerevoli ore di ricerca di una soluzione. Avrai bisogno di scoprire quali dovrebbero essere le tue impostazioni di connettività o di sperimentare (sarà ovvio se sceglierai quello sbagliato perché non sarai in grado di collegarti alla scatola sul desktop remoto, quindi assicurati di poter arrivare al macchina fisica).

È abbastanza bassa la frutta sospesa per testare questo. Ho impostato una finestra di comando con un comando ping da una delle macchine worker che eseguiva il ping del server di database e poteva vedere la perdita di pacchetti periodicamente. Una volta che ho cambiato le impostazioni della NIC e ho capito bene, il problema è andato via completamente. Ci sono diversi articoli su internet che trattano questo problema. È difficile rintracciare perché è: 1) periodico e 2) sembra qualcosa di sbagliato con gli oggetti di connessione, ecc.