У меня есть приложение Java EE, работающее на Glassfish и подключающееся к MSSQL Server 2008 через jTDS.По неизвестной причине соединение с базой данных неожиданно закрывается во время запросов.Приложение огромно, но вот краткая информация о том, как происходит ошибка:
Во время установки Glassfish с созданием пула соединений с asadmin create-jdbc-connection-pool
и asadmin create-jdbc-resource
.Класс источника данных - net.sourceforge.jtds.jdbcx.JtdsDataSource
.
. Когда Glassfish повышается, он вызывает нашу реализацию ServletContextListener.contextInitialized (), где мы выбираем источник данных из JNDI.Источник данных хранится в статической переменной.
Некоторое время все идет хорошо.Все запросы обрабатываются, и соединение не закрывается.Наше приложение выполняет обработку с использованием EJB-компонентов Timer и MDB (Message Driven Bean).
Это пример реализации 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;
}
}
В конце концов мы начинаем получать следующее исключение (происходит)около 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, иногда во время выполнения запроса.
В очень редких случаях (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)
Также в очень редких случаях (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
В редких случаях мы получаем это страшное исключение (NPE внутри 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)
...
Мы не можем найти, почему это происходит,Используемые соединения никогда не будут простаивать более секунды во время запроса.Мы не знаем, кто разрывает связь.Это может быть нестабильность сети, но тогда я думаю, что jTDS должен выдавать только исключения, связанные с сетью, верно?
Другой вариант - это некоторая политика или конфигурация пула соединений Glassfish (возможно, Glassfish преждевременно закрывает физические соединения), но как это сделать?мы отслеживаем это?
Наконец, MS SQL Server 2008 может удаленно разрывать соединения, но как мы можем отслеживать на стороне сервера, чтобы знать, происходит ли это?