c3p0 数据库宕机时重连数据库失败

C3p0 failed to reconnect the database when the database is down

我在配置 c3p0 设置时遇到了问题。 senario 是:我有一个 java 项目,每天 3:00 am 开始,然后连接到数据库做一些事情。有时,数据库可能当时宕机,可能会在2、3小时后恢复。
所以,我需要让程序在特定的时间间隔尝试重新连接数据库,看数据库是否正常,直到能够成功连接数据库。 我试图将 c3p0 配置为无限地重新连接数据库直到成功,但它似乎陷入了某种僵局。下面是我的 c3p0 设置。 我在 Spring 框架中使用 c3p0 v0.9.1 和 hibernate,数据库是 DB2.

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
    <property name="driverClass" value="${jdbc.driverClassName}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="root"/>
    <property name="password" value="root"/>

    <property name="acquireRetryAttempts" value="0"/>

    <property name="acquireRetryDelay" value="10000"/>

    <property name="maxIdleTime"value="60"/>
    <property name="minPoolSize" value="5" />
    <property name="maxPoolSize" value="200"/>
    <property name="idleConnectionTestPeriod" value="30" />
    <property name="preferredTestQuery" value="values(1)" />
</bean>

当我运行程序运行失败,错误日志如下:

[WARN]: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@21eb3f -- APPARENT DEADLOCK!!! 
Creating emergency threads for unassigned pending tasks!
[WARN]: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@21eb3f -- APPARENT DEADLOCK!!! 
Complete Status:
 Managed Threads: 3
 Active Threads: 3
 Active Tasks: 
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@15e796d (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@176150c (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1)
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@15fc793 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2)
 Pending Tasks: 
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@127bd04
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@1ea8fc0
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@83969e
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@1159092
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@c69203
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@9c035a
  com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@a0416a
Pool thread stack traces:
  ...
[WARN] [2017-09-04  ThreadPoolAsynchronousRunner.processReplacedThreads() ] Task com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask@15e796d 
(in deadlocked PoolThread) failed to complete in maximum time 60000ms. Trying interrupt().
[WARN] [2017-09-04  ThreadPoolAsynchronousRunner.processReplacedThreads() ] Task com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask@176150c 
(in deadlocked PoolThread) failed to complete in maximum time 60000ms. Trying interrupt().
[WARN] [2017-09-04  ThreadPoolAsynchronousRunner.processReplacedThreads() ] Task com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask@15fc793 
(in deadlocked PoolThread) failed to complete in maximum time 60000ms. Trying interrupt().

[WARN] [2017-09-04 BasicResourcePool$AcquireTask.run()] com.mchange.v2.resourcepool.BasicResourcePool@53b9e444 -- Thread unexpectedly interrupted
while performing an acquisition attempt.
java.lang.InterruptedException: sleep interrupted
   at java.lang.Thread.sleep(Native Method)
   at com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask.run (BasicResourcePool.java:1805)
   at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
[WARN] [2017-09-04 BasicResourcePool$AcquireTask.run()] com.mchange.v2.resourcepool.BasicResourcePool@53b9e444 -- Thread unexpectedly interrupted
while performing an acquisition attempt.
java.lang.InterruptedException: sleep interrupted
   at java.lang.Thread.sleep(Native Method)
   at com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask.run (BasicResourcePool.java:1805)
   at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
[WARN] [2017-09-04 BasicResourcePool$AcquireTask.run()] com.mchange.v2.resourcepool.BasicResourcePool@53b9e444 -- Thread unexpectedly interrupted
while performing an acquisition attempt.
java.lang.InterruptedException: sleep interrupted
   at java.lang.Thread.sleep(Native Method)
   at com.mchange.v2.resourcepol.BasicResourcePool$AcquireTask.run (BasicResourcePool.java:1805)
   at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

如果设置有问题,能帮忙指正一下吗?提前致谢!

首先,您不应该使用 c3p0-0.9.1。那是古老的。当前版本为 0.9.5.2.

这里的问题是,当您的数据库关闭时,连接尝试不会因异常而失败,它们会挂起。因此,c3p0 的线程池充满了尝试获取既不成功也不失败但无限期挂起的连接。一旦线程池完全饱和并阻塞了一段时间,c3p0 就会声明一个明显的死锁,你会看到你所看到的。

最好的办法是修复网络或服务器中导致连接到数据库的尝试挂起而不是成功或失败的任何错误。如果你能解决这个问题,你的问题可能就会消失。

如果您不能解决这个问题,您可以使用 c3p0 设置来解决这个问题,maxAdministrativeTaskTime。如果你设置这个,在你定义的秒数之后,c3p0 将认为任何挂起的任务(比如你的连接获取尝试)被破坏,并且会尝试通过在任务具有的线程上调用 interrupt() 来强制它们失败挂了。如果幸运的话,您冻结的获取任务将失败并显示 InterruptedException,生活将继续。

如果您确实使用 maxAdministrativeTaskTime,您需要设置一个比连接到数据库合理需要的时间长得多的值(当 DBMS 启动并可用时)。您可能还希望将 numHelperThreads 从其默认值 3 增加,以便不会无休止地挂起但仍然缓慢的获取任务在它们使整个线程池饱和并引发死锁之前可以使用更多线程。