0

切断されたデータベース接続からの回復に問題があります。私のテスト ケースでは、次のライブラリを使用します。
guice-persist 4.0
Hibernate コア 4.3.1
HikariCP-java6-2.3.9 (接続プール)。

私のテストは、各読み取りの間に小さなスリープを入れてループで単純な読み取りを実行します。

@com.google.inject.persist.Transactional
protected void simpleRead() {
  dao = new MyDao(....)
  dao.findBy(...)
}

Dao はこのように entityManager を取得します

@Inject
protected com.google.inject.Provider<EntityManager> entityManager;

guice モジュールはこのようにバインドされています

@Override
public void configure() {
  install(new JpaPersistModule("test"));
  bind(JPAInitializer.class).asEagerSingleton();
}

私のpersistence.xmlは、トランザクションタイプを「RESOURCE-LOCAL」と定義しています。

光の設定がいくつかありますが、これらが関連しているかどうかはわかりません

 <property name="hibernate.connection.provider_class" value="com.zaxxer.hikari.hibernate.HikariConnectionProvider" /> 
 <property name="hibernate.hikari.maxLifetime" value="1800000" />
 <property name="hibernate.hikari.connectionTestQuery" value="SELECT 1" />
 <property name="hibernate.hikari.leakDetectionThreshold" value="300000" />

テストが読み取りをループしている間、タスク マネージャーからサービスを停止して SQLServer 接続を切断します。その時点でループが simplRead() メソッドになかった場合は、次に試行された読み取りでエラーを適切に処理し、サービスが再び開始されたときに再接続します。ただし、サービスが停止したときに simpleRead() メソッドにあった場合、サービスは失敗し、回復することはありません。最初の失敗は次のように報告されます


org.hibernate.TransactionException: JDBC begin transaction failed: javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed: at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1771) at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:64) at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.invoke(JpaLocalTxnInterceptor.java:66) at net.impro.portal.server.model.dao.TestConnectionStuff.testConnectionBroken(TestConnectionStuff.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80) at org.testng.internal.Invoker.invokeMethod(Invoker.java:714) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111) at org.testng.TestRunner.privateRun(TestRunner.java:767) at org.testng.TestRunner.run(TestRunner.java:617) at org.testng.SuiteRunner.runTest(SuiteRunner.java:334) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291) at org.testng.SuiteRunner.run(SuiteRunner.java:240) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1197) at org.testng.TestNG.runSuitesLocally(TestNG.java:1122) at org.testng.TestNG.run(TestNG.java:1030) at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175) Caused by: org.hibernate.TransactionException: JDBC begin transaction failed: at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:76) at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162) at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1431) at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:61) ... 26 more Caused by: java.sql.SQLException: I/O Error: Connection reset by peer: socket write error at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1059) at net.sourceforge.jtds.jdbc.TdsCore.submitSQL(TdsCore.java:905) at net.sourceforge.jtds.jdbc.JtdsConnection.setAutoCommit(JtdsConnection.java:2291) at com.zaxxer.hikari.proxy.ConnectionProxy.setAutoCommit(ConnectionProxy.java:334) at com.zaxxer.hikari.proxy.ConnectionJavassistProxy.setAutoCommit(ConnectionJavassistProxy.java) at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:72) ... 29 more Caused by: java.net.SocketException: Connection reset by peer: socket write error at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(Unknown Source) at java.net.SocketOutputStream.write(Unknown Source) at java.io.DataOutputStream.write(Unknown Source) at net.sourceforge.jtds.jdbc.SharedSocket.sendNetPacket(SharedSocket.java:717) at net.sourceforge.jtds.jdbc.RequestStream.putPacket(RequestStream.java:570) at net.sourceforge.jtds.jdbc.RequestStream.flush(RequestStream.java:518) at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1046) ... 34 more ...

そして、それが適切にクリーンアップされないため、後続のリクエストは次のように失敗します

org.hibernate.TransactionException: Already have an associated managed connection

この問題の原因となっているレイヤーを特定するのは簡単ではありません。私が読んだことから、接続プールは壊れた接続をテストしてクリーンアップする必要がありますが、スレッドローカルオブジェクトに関連付けられた壊れた EntityManager 参照を永久に保持する guice-persist が疑われます。もちろん、それは私がそれらを使用する方法でもあるかもしれません.

編集

さらに調査した結果、各テスト読み取りの間に 1000 ミリ秒以上待機すると、コードが期待どおりに動作することに気付きました。以下の StackTrace を取得し、SQLServer サービスを復元すると、問題なく再接続されます。1000 ミリ秒未満の場合、元の投稿で上記のエラーが表示されます。休止状態は IO/Error を同じ方法で処理しないようで、接続は永久に壊れた状態のままです。

javax.persistence.QueryTimeoutException: Could not open connection
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1725)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1771)
    at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:64)
    at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.invoke(JpaLocalTxnInterceptor.java:66)
    at net.impro.portal.server.model.dao.TestConnectionStuff.testConnectionBroken(TestConnectionStuff.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1197)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1122)
    at org.testng.TestNG.run(TestNG.java:1030)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: org.hibernate.QueryTimeoutException: Could not open connection
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:83)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:235)
    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:171)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:67)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162)
    at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1471)
    at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:61)
    ... 26 more
Caused by: java.sql.SQLTimeoutException: Timeout after 30004ms of waiting for a connection.
    at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:233)
    at com.zaxxer.hikari.pool.BaseHikariPool.getConnection(BaseHikariPool.java:183)
    at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:93)
    at com.zaxxer.hikari.hibernate.HikariConnectionProvider.getConnection(HikariConnectionProvider.java:101)
    at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:380)
    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:228)
    ... 31 more
Caused by: java.sql.SQLException: Network error IOException: Connection refused: connect
    at net.sourceforge.jtds.jdbc.JtdsConnection.<init>(JtdsConnection.java:436)
    at net.sourceforge.jtds.jdbc.Driver.connect(Driver.java:184)
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:95)
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:101)
    at com.zaxxer.hikari.pool.BaseHikariPool.addConnection(BaseHikariPool.java:444)
    at com.zaxxer.hikari.pool.BaseHikariPool$1.run(BaseHikariPool.java:419)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at net.sourceforge.jtds.jdbc.SharedSocket.createSocketForJDBC3(SharedSocket.java:288)
    at net.sourceforge.jtds.jdbc.SharedSocket.<init>(SharedSocket.java:251)
    at net.sourceforge.jtds.jdbc.JtdsConnection.<init>(JtdsConnection.java:331)
    ... 10 more
4

2 に答える 2

2

どのバージョンの jTDS を使用していますか? そのバージョンのドライバーは、'08' (切断を示す) で始まる SQLState 値を含む でSocketExceptionラップされていないようです。SQLException

HikariCPはこれらの SQLStatesをチェックし、エビクションの接続にフラグを立てます。その接続は閉じて、二度と戻らないようにする必要があります。

新しいバージョンの jTDS ドライバー、コードを正しく読み取っていれば、正しく処理されているようです。

更新: もちろん、これは Hibernate が例外の後も接続を閉じることを前提としています (finally ブロックのように)。

更新 2: 2 番目の例外部分を見逃しました。これは、Hibernate の問題のように見えます...最初の例外から適切に回復していません。パッケージのロギングを有効にするとcom.zaxxer.hikari、接続が削除されているという警告が表示されます。あなた見えますか?

UPDATE3: jTDS 1.3.0 を見たところ、正しいことをしています。ここで、SQLState="08S01" で SQLException が生成されることがわかります。これは、HikariCP によってチェックされ、接続が削除されます。

より多くの疑惑が Hibernate にあるようになりました。今は彼らのコードを見る時間がありませんが、スタックトレースの行番号を使って見ることをお勧めします。

于 2015-08-07T09:24:22.783 に答える
0

私はついに問題を発見しました。これは、「ブロッカー」ステータスの既知の休止状態のバグです。

合理的な回避策がなければ、データベースの回復は不可能であるか、少なくとも非常に非現実的です。

于 2015-08-12T09:32:10.723 に答える