数据库宕机时C3p0重新连接数据库失败

Posted

技术标签:

【中文标题】数据库宕机时C3p0重新连接数据库失败【英文标题】:C3p0 failed to reconnect the database when the database is down 【发布时间】:2017-09-06 06:29:14 【问题描述】:

我在配置 c3p0 设置时遇到了问题。情景是:我有一个 java 项目,每天凌晨 3:00 开始,然后连接到数据库做一些事情。有时,当时数据库可能已关闭,可能会在 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)

如果设置有问题,您能帮我纠正一下吗?提前谢谢!

【问题讨论】:

这个application是怎么开始的?定时任务? @Scary 是的。 那么你可以尝试使用工具,例如db 客户端 cli,在尝试启动您的应用程序之前测试数据库是否已启动并将其放入您的应用程序启动脚本中 @Scary Wombat 可能无法这样做。 什么意思?看dbforums.com/… 【参考方案1】:

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

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

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

如果您无法解决此问题,您可以使用 c3p0 设置 maxAdministrativeTaskTime 轻松解决该问题。如果你设置了这个,在你定义的秒数之后,c3p0 将考虑任何挂起的任务(比如你的连接获取尝试)被破坏,并试图通过在任务挂起的线程上调用 interrupt() 来强制它们失败。如果幸运的话,您的冻结获取任务将失败并返回 InterruptedException,然后生活将继续。

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

【讨论】:

感谢您的详细解释,我会根据您的建议尝试新版本。

以上是关于数据库宕机时C3p0重新连接数据库失败的主要内容,如果未能解决你的问题,请参考以下文章

jdbc c3p0连接mysql 失败 原因汇总,求助

C3P0连接池一些基本配置

c3p0连接池配置

C3P0配置属性

使用 c3p0 连接池丢失 MySQL 连接

c3p0数据源配置