DBUnit и SQL Server закрывают сокет - PullRequest
0 голосов
/ 28 августа 2009

Я получаю это исключение с 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 Ответ

2 голосов
/ 03 сентября 2009

После некоторой значительной игры с этим был другой код теста кода, который считывал метаданные, но не закрывал набор результатов. Теперь проблема ушла.

Моя теория состоит в следующем. Чтобы получить метаданные базы данных в MSSQL, вам необходимо подключиться к базе данных, отличной от текущей. Один из способов сделать это - изменить базы данных (в MSSQL есть команда use). Проблема с этим подходом заключается в том, что вы можете испортить транзакцию с текущим соединением и вызвать проблемы с многопоточностью, если к одному соединению подключено несколько потоков.

Таким образом, решение могло открыть отдельное соединение под капотом, но совместно использовать один объект соединения для всего соединения, если не для всей виртуальной машины. JDBC предоставляет только набор результатов, который может быть закрыт, поэтому они могут поместить финализатор, который закрывает соединение, если вы не вызвали close для набора результатов и закрыли его самостоятельно. Проблема в том, что если кто-то читает метаданные одновременно, соединение закрывается из-под него, и, следовательно, происходит сбой.

Учитывая, что эти тестовые прогоны проходили по очень согласованному пути кода, вполне возможно, что шаблон использования памяти был довольно стабильным при запуске, что приводило к тому, что сборка мусора происходила в одно и то же время, но не всегда в одно и то же время. , что соответствует наблюдению, что оно не всегда падало в одном и том же месте.

Это теория. Я не уверен, как это подтвердить, но если проблема не вернется, это мое предположение. Извлеченный урок: всегда закрывайте набор результатов, читая метаданные (и вообще).

РЕДАКТИРОВАТЬ (через долгое время): Хотя в целом вышеупомянутое все еще может быть правдой, в коде произошла другая проблема - он использовал сам финализатор. Таким образом, у вас была обертка вокруг соединения, которое закрывало соединение в финализаторе, но позволяло открывать соединение другим. Еще одно важное правило кодирования: если ваш финализатор закрывает ресурсы, всегда следите за тем, чтобы ничто не могло получить к ним доступ, не имея ссылки на класс, содержащий их.

...