Glassfish,jTDS和SQL Server 2008意外关闭了数据库连接

时间:2011-11-18 01:15:12

标签: java sql-server jdbc glassfish jtds

我有一个在Glassfish上运行的Java EE应用程序,并通过jTDS连接到MSSQL Server 2008。由于某些未知原因,数据库连接在请求期间意外关闭。该应用程序是巨大的,但这里是错误发生的总结:

在Glassfish设置期间,创建一个包含asadmin create-jdbc-connection-poolasadmin create-jdbc-resource的连接池。数据源类为net.sourceforge.jtds.jdbcx.JtdsDataSource

当Glassfish上升时,它调用我们的ServletContextListener.contextInitialized()实现,我们从JNDI获取数据源。数据源存储在静态变量中。

有一段时间,一切都很顺利。处理所有请求,不关闭任何连接。我们的应用程序使用Timer和MDB(消息驱动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;
  }
}

最终,我们开始得到以下异常(在一小时内发生约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

在极少数情况下,我们会遇到这个可怕的例外(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)
  ...

我们无法找到这种情况发生的原因。在请求期间,使用的连接永远不会空闲超过一秒。我们不知道是谁放弃了连接。这可能是网络不稳定,但我猜jTDS应该只产生与网络相关的异常,对吗?

另一个选择是Glassfish连接池的某些策略或配置(也许Glassfish过早关闭物理连接),但我们如何跟踪它?

最后,MS SQL Server 2008可以远程删除连接,但我们如何监控服务器端以了解它是否正在发生?

2 个答案:

答案 0 :(得分:2)

我的应用程序几乎完全接收了这些类型的异常。我的所有机器都是全新的服务器,所有网卡都设置为自动检测网络速度。它们都连接到100MB /秒HALF双工的旧交换机。

将该交换机上的所有计算机设置为明确使用100MB /秒HALF双工连接设置而不是自动检测是在经过无数个小时搜索解决方案后对我有用的。您需要了解您的连接设置应该是什么或进行实验(如果您选择了错误的连接设置,将会很明显,因为您将无法通过远程桌面连接到该框,因此请确保您可以访问物理机器)。

测试这个是非常低的成果。我使用ping命令设置一个命令窗口,其中一个工作机器ping数据库服务器,并且可以定期看到丢包。一旦我更改了NIC设置并正确完成,问题就完全消失了。互联网上有几篇关于这个问题的文章。很难追踪,因为它是:1)周期性的,2)看起来连接对象有问题等。

答案 1 :(得分:1)

尝试使用SQL Server Profiler http://msdn.microsoft.com/en-us/library/ms187929.aspx 您可以从模板“标准”开始,因为它包含事件:审核登录,审核注销,ExistingConnection http://msdn.microsoft.com/en-us/library/ms190176.aspx 我认为它们对你来说最重要