DBUnit和SQL Server关闭套接字

时间:2009-08-27 22:11:26

标签: java sql-server dbunit

我在同一个地方继续使用DBUnit获取此异常:

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个数据库测试,但同一个是失败的(当它失败时)。

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

1 个答案:

答案 0 :(得分:2)

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

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

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

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

这就是理论。我不确定如何确认,但除非问题回来,这是我的假设。获得的经验:始终通过读取元数据(通常)来关闭结果集。

编辑(经过很长一段时间):虽然一般来说上面的内容可能仍然存在,但代码中还有另一个问题 - 它本身就是使用终结器。所以你有一个连接器的封装器,它正在关闭终结器中的连接,但让连接暴露给其他人。另一个重要的编码规则:如果你的终结器关闭资源,总是确保没有任何东西可以访问这些资源而不必引用包含它们的类。