【问题标题】:Java / Hibernate in client with reconnect客户端中的 Java / Hibernate 重新连接
【发布时间】:2015-02-04 18:30:37
【问题描述】:

我有一个 24/7 运行的 mysql 服务器和许多使用 JPA / Hibernate 访问数据库的 SWT 富客户端......

如果客户端计算机(笔记本电脑)进入休眠/待机状态并在一段时间后唤醒,则数据库连接丢失 - 无论哪种设置和/或数据库连接提供程序(我尝试过 c3p0 和 vibur)我使用....

这是我当前的 hibernate.xml 属性文件(也不起作用)...:

    <property name="connection.pool_size">3</property>
    <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <property name="hibernate.cache.use_query_cache">false</property>

    <property name="hibernate.current_session_context_class">thread</property>

    <property name="hibernate.c3p0.validate">true</property>
    <property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">600</property>
    <property name="hibernate.c3p0.timeout">0</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
    <property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
    <property name="hibernate.c3p0.testConnectionOnCheckin">true</property>
            <property name="hibernate.c3p0.idle_test_period">3000</property>
    <property name="hibernate.c3p0.acquireRetryAttempts">10</property>
    <property name="hibernate.c3p0.acquireRetryDelay">1000</property>
    <property name="hibernate.c3p0.breakAfterAcquireFailure">false</property>

这是一个错误堆栈跟踪:

WARN | 02.12.2014 21:35:06,503 | [C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-AdminTaskTimer] | ThreadPoolAsynchronousRunner:743 | com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@89789 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
 WARN | 02.12.2014 21:35:06,507 | [C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-AdminTaskTimer] | ThreadPoolAsynchronousRunner:759 | com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@89789 -- APPARENT DEADLOCK!!! Complete Status: 
    Managed Threads: 3
    Active Threads: 3
    Active Tasks: 
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@b76a87
            on thread: C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#0
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@1b2ffe7
            on thread: C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#1
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@becbe1
            on thread: C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#2
    Pending Tasks: 
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@3b2d78
Pool thread stack traces:
    Thread[C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#0,5,main]
        java.net.DualStackPlainSocketImpl.connect0(Native Method)
        java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
        java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
        java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        java.net.Socket.connect(Socket.java:579)
        java.net.Socket.connect(Socket.java:528)
        java.net.Socket.<init>(Socket.java:425)
        java.net.Socket.<init>(Socket.java:241)
        com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:259)
        com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:307)
        com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2482)
        com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2519)
        com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2304)
        com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:834)
        com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
        sun.reflect.GeneratedConstructorAccessor249.newInstance(Unknown Source)
        sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:416)
        com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:346)
        com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:146)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:195)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:184)
        com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
        com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:44)
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
    Thread[C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#2,5,main]
        java.net.DualStackPlainSocketImpl.connect0(Native Method)
        java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
        java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
        java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        java.net.Socket.connect(Socket.java:579)
        java.net.Socket.connect(Socket.java:528)
        java.net.Socket.<init>(Socket.java:425)
        java.net.Socket.<init>(Socket.java:241)
        com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:259)
        com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:307)
        com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2482)
        com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2519)
        com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2304)
        com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:834)
        com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
        sun.reflect.GeneratedConstructorAccessor249.newInstance(Unknown Source)
        sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:416)
        com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:346)
        com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:146)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:195)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:184)
        com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
        com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:44)
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
    Thread[C3P0PooledConnectionPoolManager[identityToken->1hge13a96372xk9xvyjyj|1dd3180]-HelperThread-#1,5,main]
        java.net.DualStackPlainSocketImpl.connect0(Native Method)
        java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
        java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
        java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        java.net.Socket.connect(Socket.java:579)
        java.net.Socket.connect(Socket.java:528)
        java.net.Socket.<init>(Socket.java:425)
        java.net.Socket.<init>(Socket.java:241)
        com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:259)
        com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:307)
        com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2482)
        com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2519)
        com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2304)
        com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:834)
        com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
        sun.reflect.GeneratedConstructorAccessor249.newInstance(Unknown Source)
        sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:416)
        com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:346)
        com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:146)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:195)
        com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:184)
        com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
        com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
        com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:44)
        com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
        com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)


 WARN | 03.12.2014 10:29:20,014 | [main] | SqlExceptionHelper:145 | SQL Error: 0, SQLState: 08S01
ERROR | 03.12.2014 10:29:20,015 | [main] | SqlExceptionHelper:147 | The last packet successfully received from the server was 65.896.659 milliseconds ago.  The last packet sent successfully to the server was 65.896.672 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.

【问题讨论】:

    标签: java mysql hibernate jpa c3p0


    【解决方案1】:

    当数据库服务器(或笔记本电脑客户端)出现故障时,正在获取新数据库连接的线程被卡住了。它们与 DBMS 处于中间通信状态,只是挂起。他们既没有成功获得连接,也没有立即失败并出现异常。这些挂起的线程使您的线程池饱和,从而阻止了各种任务的完成。一段时间后,c3p0 声明一个 APPARENT DEADLOCK!,然后丢弃并替换其线程池中的所有线程以重新开始。通常应用程序在出现明显的死锁后恢复并正常运行!但是,如果因中断而中断的连接尝试既没有成功也没有失败并出现异常,您可能偶尔会看到这些死锁。

    一些事情可能会有所帮助。如果连接获取尝试被卡住的 I/O 操作是可中断的,那么您可以通过设置 maxAdministrativeTaskTime 来防止明显的死锁。但是如果 I/O 是不可中断的,那就行不通了。

    如果您经常看到这些死锁,这可能意味着您处理连接的速度太快了。在经过良好调整的池中,连接获取尝试应该很少见,因此在多次获取中发生中断也应该很少见。上面的配置中没有任何内容会导致您流失连接,但是您说您引用的配置“不起作用”,所以可能真正的 c3p0 配置不同。 c3p0 DataSource 在池 init 上以 INFO 级别转储其配置。如果你搜索你的日志,你可以验证你想要的配置是否真的是你的 c3p0 数据源的配置。

    【讨论】:

      【解决方案2】:

      由于它们都挂在连接上,请尝试为 MySQL JDBC 驱动程序设置一个connectTimeout(在MySQL connector J documentation 中提到)。默认情况下,没有可能让它们永远挂起的超时。

      进入待机和唤醒是您应该在客户端应用程序中捕获的内容,以便您可以采取措施防止错误(例如,关闭数据库连接然后打开新连接)。请参阅this answer 了解如何捕获其中一些此类事件,不幸的是,答案不包括WM_POWERBROADCAST 事件(在Windows 上)的示例,该事件似乎表示待机/唤醒。我确实找到了一篇关于 Windows (YMMV) 的 StandByDetector 的文章。

      当您使用它时,您可能想尝试使用HikariCP 数据库连接池而不是 c3p0(我怀疑 HikariCP 更擅长从断开的数据库连接中恢复)。您可以浏览 setup-demo HibHik 开始使用。

      【讨论】:

        【解决方案3】:

        试试 HikariCP。 See our DB-down torture test。这仅适用于支持 Connection.setNetworkTimeout() 的良好现代驱动程序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-27
          • 2020-09-05
          • 2021-03-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多