Соединение с базой данных неожиданно закрыто с помощью Glassfish, jTDS и SQL Server 2008

У меня есть приложение Java EE, работающее на Glassfish и подключающееся к MSSQL Server 2008 через jTDS. По неизвестной причине соединение с базой данных неожиданно закрывается во время запросов.Приложение огромно, но вот краткое описание того, как происходит ошибка:

Во время установки Glassfish, с созданием пула соединений с помощью asadmin create-jdbc-connection-pool и asadmin create- jdbc-ресурс . Класс источника данных - 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 может удаленно разрывать соединения, но как мы можем отслеживать серверную часть, чтобы узнать, происходит ли это?

5
задан fernacolo 18 November 2011 в 10:42
поделиться