2009-08-27 128 views
0

我不断收到此异常用DbUnit在同一个地方:DbUnit和SQL Server快速插座关闭

org.dbunit.dataset.DataSetException: com.microsoft.sqlserver.jdbc.SQLServerException: Socket closed 
at org.dbunit.database.DatabaseTableMetaData.getColumns(DatabaseTableMetaData.java:359) 

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Socket closed 
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(Unknown Source) 
at com.microsoft.sqlserver.jdbc.TDSChannel.read(Unknown Source) 
at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(Unknown Source) 
at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(Unknown Source) 
at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(Unknown Source) 
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQueryInternal(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetFromStoredProc(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetWithProvidedColumnNames(Unknown Source) 
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getColumns(Unknown Source) 
at org.dbunit.database.DefaultMetadataHandler.getColumns(DefaultMetadataHandler.java:52) 
at org.dbunit.database.DatabaseTableMetaData.getColumns(DatabaseTableMetaData.java:315) 
... 15 more 

试图读取来自列元数据时,会出现这种情况表。执行此操作的代码如下所示:

new DefaultTable(tableName, 
        Columns.getColumns(columns, 
          connection.createDataSet(new String[]{tableName}) 
            .getTableMetaData(tableName).getColumns() 
        ) 
      ) 

连接是MsSqlConnection实例。起初我认为这是一个网络问题,但是这个理论有两个问题。首先运行测试的服务器和数据库都是同一个xen服务器上的虚拟机,所以没有真正的网络。其次,虽然问题不一致,但每次都发生在同一个地方。有超过100个数据库测试,但同一个失败(失败时)。

有没有人跑过类似的问题?任何见解?

+0

你看,如果你的测试之间有任何耦合... 如果它“随机失败”,你可能会改变以前的测试环境。 – 2009-08-27 22:19:30

+0

这是一个很好的建议,但我没有看到耦合。数据库连接似乎每次都会创建并关闭。 – Yishai 2009-08-27 22:25:24

+0

我们在虚拟机中运行一些软件时遇到了奇怪的网络问题。在一个案例中,我们的源代码管理系统会随机丢失连接。我们最终放弃并将其移至自己的专用盒子中。可能不适合你,但我想我会把它扔在那里。 – 2009-08-27 22:35:46

回答

2

经过一些有意义的演示之后,还有其他代码测试代码正在读取元数据但未关闭结果集。问题现在消失了。

我的理论如下。为了在MSSQL中获取数据库元数据,您必须连接到与当前连接不同的数据库。一种方法是更改​​数据库(MSSQL中有一个使用命令)。这种方法的问题在于,你可能会将当前连接的事务搞乱,并且如果多个线程访问同一个连接,就会引入线程问题。

因此,解决方案可能会在引擎盖下打开单独的连接,但共享一个连接对象用于整个连接,如果不是整个虚拟机。 JDBC只公开一个可以关闭的结果集,所以如果你没有在结果集上调用close并关闭它,他们可能会放置一个关闭连接的终结器。问题在于,如果别的东西在同一时间读取元数据,它的连接就会从它下面关闭,因此我的崩溃。

鉴于这些测试运行发生在非常一致的代码路径上,内存使用模式肯定有可能运行时相当稳定,导致垃圾收集同时发生,但并不总是完全相同时间,这符合它并不总是在完全相同的地方崩溃的观察。

这就是理论。我不确定如何确认,但除非问题再次出现,这是我的假设。获得的经验:总是关闭阅读元数据的结果集(一般来说)。编辑(很长一段时间后):尽管总体上上述可能仍然如此,但代码中还存在另一个问题 - 它使用了终结器本身。所以你有一个关于连接的封装器,它关闭了终结器中的连接,但让连接暴露给其他人。另一个重要的编码规则:如果您的终结器关闭资源,请务必确保没有引用包含它们的类的任何内容都不能访问这些资源。