1

我一直在同一个地方使用 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 个数据库测试,但同样的一个是失败的(当它失败时)。

有没有人遇到过类似的问题?有什么见解吗?

4

1 回答 1

5

在对此进行了一些重要的尝试之后,还有其他代码测试代码正在读取元数据但没有关闭结果集。现在问题消失了。

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

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

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

这就是理论。我不确定如何确认,但除非问题再次出现,否则这是我的假设。经验教训:总是从读取元数据(和一般情况下)关闭结果集。

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

于 2009-09-03T16:33:36.620 回答