Java Glassfish、jTDS和SQL Server 2008的数据库连接意外关闭

Java Glassfish、jTDS和SQL Server 2008的数据库连接意外关闭,java,sql-server,jdbc,glassfish,jtds,Java,Sql Server,Jdbc,Glassfish,Jtds,我有一个JavaEE应用程序运行在Glassfish上,并通过jTDS连接到MSSQL Server 2008。由于未知原因,数据库连接在请求期间意外关闭。应用程序非常庞大,但下面是错误发生方式的总结: 在Glassfish安装过程中,使用asadmin创建jdbc连接池和asadmin创建jdbc资源创建连接池。数据源类是net.sourceforge.jtds.jdbcx.jtdsdsdatasource 当Glassfish启动时,它调用ServletContextListener.con

我有一个JavaEE应用程序运行在Glassfish上,并通过jTDS连接到MSSQL Server 2008。由于未知原因,数据库连接在请求期间意外关闭。应用程序非常庞大,但下面是错误发生方式的总结:

在Glassfish安装过程中,使用
asadmin创建jdbc连接池
asadmin创建jdbc资源
创建连接池。数据源类是
net.sourceforge.jtds.jdbcx.jtdsdsdatasource

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

有一段时间,一切都很顺利。所有请求均已处理,且未关闭任何连接。我们的应用程序使用计时器和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次):

异常发生在随机的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)
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
在非常罕见的情况下(一小时内5次),我们也会遇到以下例外情况:

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)
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
在极少数情况下,我们会遇到这种可怕的异常(JTD中的NPE):

我们不知道为什么会这样。在请求期间,使用的连接的空闲时间不会超过一秒钟。我们不知道是谁在断开连接。这可能是网络不稳定,但我想JTD应该只产生与网络相关的异常,对吗

另一个选项是Glassfish连接池的某些策略或配置(可能Glassfish过早地关闭了物理连接),但我们如何跟踪它呢


最后,MS SQL Server 2008可以远程断开连接,但我们如何监控服务器端以了解是否发生了这种情况?

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

在我花了无数个小时寻找解决方案之后,将该交换机上的所有机器设置为显式使用100MB/秒半双工连接设置,而不是自动感知,这对我来说非常有用。您需要找出您的连接设置应该是什么或进行什么实验(如果您选择了错误的设置,这将很明显,因为您将无法通过远程桌面连接到机箱,因此请确保您可以访问物理机器)


测试这一点是非常容易的。我设置了一个命令窗口,其中一台工作机器对数据库服务器发出ping命令,可以定期查看数据包丢失情况。一旦我更改了NIC设置并正确操作,问题就完全消失了。网上有几篇关于这个问题的文章。很难追踪,因为它是:1)周期性的,2)连接对象似乎有问题,等等。

尝试使用SQL server Profiler 您可以从模板“Standard”开始,因为它包含以下事件:审核登录、审核注销、ExistingConnection
我认为它们对您最重要

使用Microsofts JDBC驱动程序时是否也会出现问题?@extranon我们没有测试Microsoft JDBC驱动程序。有一个完整的基于JTD的持久层,切换到MS需要几天时间才能完成。您的代码是否捕获/忽略SQLException?您使用的是基本数据源还是连接池?我不认为我们忽略了异常,因为堆栈跟踪来自正常的执行流,而不是来自
finally
catch
块内部。我们使用的是Glassfish提供的基本数据源,它应该实现一个连接池。我们没有使用ConnectionPoolDataSource API,例如
getPooledConnection()
。onMessage是否在一个Servlet中?尝试声明连接本地而不是类属性。