数据库重置后重新连接 HikariCP
Reconnect HikariCP after DB reset
这类似于我大约 2 年前发布的 问题。
我有一个连续从数据库中读取的简单测试。我 stop/start 我的 SQL 服务器实例。
@Test
public void testConnectionReset() {
while (true) {
try {
simpleRead();
}
catch (Exception e) {
e.printStackStrace();
}
}
@com.google.inject.persist.Transactional
protected void simpleRead() {
dao = new MyDao(....)
dao.findBy(...)
}
如果错误发生在simpleRead()中,则全部正确处理。如果错误发生在testConnectionReset(),我有如下stackTrace,重启数据库后没有reconnect。
[2017-Dec-21 10:47:26] - [ERROR] - I/O Error: Connection reset by peer: socket write error
org.hibernate.TransactionException: Unable to rollback against JDBC Connection
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:121)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:250)
at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:100)
at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.rollbackIfNecessary(JpaLocalTxnInterceptor.java:153)
at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.invoke(JpaLocalTxnInterceptor.java:74)
at temp.testConnection(TestConnection.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
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:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:236)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:81)
Caused by: java.sql.SQLException: Connection is closed
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection[=11=](ProxyConnection.java:490)
at com.sun.proxy.$Proxy84.rollback(Unknown Source)
at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:377)
at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java)
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116)
... 29 more
我目前的解决方法是将 com.zaxxer.hikari.aliveBypassWindowMs
设置为 0,每次在池返回之前强制进行连接检查。我发现很难相信这是一个 Hikari 错误,因为我没有看到其他人有这个问题,所以也许它是我缺少的其他配置。
我的筹码是
- 列表项
- SQL 服务器
- JTDS (1.3.1) 驱动程序。 (我试过 SQL 服务器驱动程序,结果相似)
- HikariCP (2.7.4)
- Google 指南 (4.1.0)
- 休眠 (5.2.11)
这是 guice-persist 中的错误。它与 this 一个密切相关。简单的事件流程是这样的
- Hikari 在池中有一个有效连接
- 与数据库的连接丢失
- 调用 Guice-presist @Transactional,并从池中拉取连接(未选中)。
- Guice 执行 txn.begin(),抛出异常但无法结束 unitOfWork / closeConnection。池仍然处于错误状态。
我找到的解决方法是以下之一
- 手动处理 unitOfWork。
- 通过将 aliveBypassWindowMs 设置为 0,要求 Hikari 每次从连接池返回时检查连接。
- 通过在必要时结束 unitOfWork 直接修改有问题的 class (JpaLocalTxnInterceptor)。
这类似于我大约 2 年前发布的
我有一个连续从数据库中读取的简单测试。我 stop/start 我的 SQL 服务器实例。
@Test
public void testConnectionReset() {
while (true) {
try {
simpleRead();
}
catch (Exception e) {
e.printStackStrace();
}
}
@com.google.inject.persist.Transactional
protected void simpleRead() {
dao = new MyDao(....)
dao.findBy(...)
}
如果错误发生在simpleRead()中,则全部正确处理。如果错误发生在testConnectionReset(),我有如下stackTrace,重启数据库后没有reconnect。
[2017-Dec-21 10:47:26] - [ERROR] - I/O Error: Connection reset by peer: socket write error
org.hibernate.TransactionException: Unable to rollback against JDBC Connection
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:121)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:250)
at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:100)
at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.rollbackIfNecessary(JpaLocalTxnInterceptor.java:153)
at com.google.inject.persist.jpa.JpaLocalTxnInterceptor.invoke(JpaLocalTxnInterceptor.java:74)
at temp.testConnection(TestConnection.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
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:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:132)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:236)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:81)
Caused by: java.sql.SQLException: Connection is closed
at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection[=11=](ProxyConnection.java:490)
at com.sun.proxy.$Proxy84.rollback(Unknown Source)
at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:377)
at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java)
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116)
... 29 more
我目前的解决方法是将 com.zaxxer.hikari.aliveBypassWindowMs
设置为 0,每次在池返回之前强制进行连接检查。我发现很难相信这是一个 Hikari 错误,因为我没有看到其他人有这个问题,所以也许它是我缺少的其他配置。
我的筹码是
- 列表项
- SQL 服务器
- JTDS (1.3.1) 驱动程序。 (我试过 SQL 服务器驱动程序,结果相似)
- HikariCP (2.7.4)
- Google 指南 (4.1.0)
- 休眠 (5.2.11)
这是 guice-persist 中的错误。它与 this 一个密切相关。简单的事件流程是这样的
- Hikari 在池中有一个有效连接
- 与数据库的连接丢失
- 调用 Guice-presist @Transactional,并从池中拉取连接(未选中)。
- Guice 执行 txn.begin(),抛出异常但无法结束 unitOfWork / closeConnection。池仍然处于错误状态。
我找到的解决方法是以下之一
- 手动处理 unitOfWork。
- 通过将 aliveBypassWindowMs 设置为 0,要求 Hikari 每次从连接池返回时检查连接。
- 通过在必要时结束 unitOfWork 直接修改有问题的 class (JpaLocalTxnInterceptor)。