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インスタンスである接続。最初はネットワークの問題だと思っていましたが、その理論には2つの問題があります。まず、テストを実行するサーバーとデータベースは両方とも同じxenサーバー上の仮想マシンであるため、実際のネットワークはありません。第二に、問題は一貫していませんが、毎回同じ場所で発生します。100を超えるデータベーステストがありますが、これと同じものが失敗します(失敗した場合)。

誰かが同様の問題に遭遇しましたか?洞察はありますか?

4

1 に答える 1

5

これをかなり試した後、メタデータを読み取っていたが結果セットを閉じていない他のコードテストコードがありました。問題はなくなりました。

私の理論は次のとおりです。MSSQLでデータベースメタデータを取得するには、現在の接続とは異なるデータベースに接続する必要があります。これを行う1つの方法は、データベースを変更することです(MSSQLにはuseコマンドがあります)。このアプローチの問題は、現在の接続でトランザクションを台無しにする可能性があり、複数のスレッドが同じ接続にアクセスするとスレッドの問題が発生する可能性があることです。

そのため、ソリューションは内部で個別の接続を開く可能性がありましたが、VM全体ではなくても、接続全体で1つの接続オブジェクトを共有していました。JDBCは、閉じることができる結果セットのみを公開するため、結果セットに対してcloseを呼び出して自分で閉じていない場合は、接続を閉じるファイナライザーを配置している可能性があります。それに関する問題は、他の何かが同時にメタデータを読み取っている場合、その下から接続が閉じられているため、クラッシュすることです。

これらのテスト実行が非常に一貫したコードパスで行われていたことを考えると、メモリ使用パターンが実行するのにかなり安定していた可能性があり、ガベージコレクションが同時に発生しますが、常に正確に同時に発生するとは限りません。常に同じ場所でクラッシュするとは限らないという観察結果。

それが理論です。確認方法はわかりませんが、問題が再発しない限り、それが私の想定です。教訓:メタデータ(および一般的に)の読み取りからの結果セットを常に閉じます。

編集(久しぶり):一般的に上記はまだ正しいかもしれませんが、コードで起こっている別の問題がありました-それはファイナライザー自体を使用していました。そのため、ファイナライザーで接続を閉じていたが、接続を他のユーザーに公開する接続のラッパーがありました。もう1つの重要なコーディング規則:ファイナライザーがリソースを閉じる場合は、それらを含むクラスへの参照がなければ、それらのリソースにアクセスできるものがないことを常に確認してください。

于 2009-09-03T16:33:36.620 に答える