Glassfishで実行されているJavaEEアプリケーションがあり、jTDSを介してMSSQLServer2008に接続しています。なんらかの理由で、データベース接続がリクエスト中に予期せず閉じられます。アプリケーションは巨大ですが、エラーがどのように発生するかの概要は次のとおりです。
Glassfishのセットアップ中に、とで接続プールを作成しasadmin create-jdbc-connection-pool
ますasadmin create-jdbc-resource
。データソースクラスはnet.sourceforge.jtds.jdbcx.JtdsDataSource
です。
Glassfishが起動すると、ServletContextListener.contextInitialized()の実装が呼び出され、JNDIからデータソースがフェッチされます。データソースは静的変数に保存されます。
しばらくの間、すべてがうまくいきます。すべてのリクエストが処理され、接続は閉じられません。このアプリケーションは、TimerおよびMDB(Message Driven Bean)EJBを使用して処理を実行します。
これはサンプル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;
}
}
最終的に、次の例外が発生し始めます(1時間に約100回発生します)。
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)
例外はランダムなJDBC呼び出しで発生します。ResultSetの反復中の場合もあれば、クエリの実行中の場合もあります。
非常にまれなケース(1時間に7回)では、次の例外が発生します。
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)
また、非常にまれなケース(1時間に5回)では、次の例外が発生します。
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
まれに、この恐ろしい例外(jTDS内のNPE)が発生します。
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)
...
なぜこれが起こるのかわかりません。使用された接続は、要求中に1秒を超えてアイドル状態になることはありません。誰が接続を切断しているのかわかりません。ネットワークが不安定な場合もありますが、jTDSではネットワーク関連の例外のみが発生するはずです。
もう1つのオプションは、Glassfish接続プールのポリシーまたは構成です(Glassfishが物理接続を途中で閉じている可能性があります)が、どのように追跡できますか?
最後に、MS SQL Server 2008はリモートで接続を切断する可能性がありますが、サーバー側を監視して、接続が発生しているかどうかを確認するにはどうすればよいでしょうか。