在使用c3p0数据池时,如果连接池参数配置不当,可能会引发一个意想不到的问题。
数据库:Oracle
c3p0版本:0.9.5.2
数据源配置:
application.xml

<bean id="dataSource" name="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 指定连接数据库的驱动 --><property name="driverClass" value="${jdbc.driverClassName}" /><!-- 指定连接数据库的URL --><property name="jdbcUrl" value="${jdbc.url}" /><!-- 指定连接数据库的用户名 --><property name="user" value="${jdbc.user}" /><!-- 指定连接数据库的密码 --><property name="password" value="${jdbc.pass}" /><!-- 指定连接池中保留的最大连接数. Default:15 --><property name="maxPoolSize" value="${jdbc.maxPoolSize}" /><!-- 指定连接池中保留的最小连接数 --><property name="minPoolSize" value="${jdbc.minPoolSize}" /><!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3 --><property name="initialPoolSize" value="${jdbc.initialPoolSize}" /><!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0 --><property name="maxIdleTime" value="${jdbc.maxIdleTime}" /><!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3 --><property name="acquireIncrement" value="${jdbc.acquireIncrement}" /><!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。 但由于预缓存的statements属于单个connection而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0 --><property name="maxStatements" value="${jdbc.maxStatements}" /><!-- 每60秒检查所有连接池中的空闲连接.Default:0 --><property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}" /></bean>

dataSource.properties

 jdbc.initialPoolSize=20jdbc.maxPoolSize=100jdbc.minPoolSize=10jdbc.maxIdleTime=600jdbc.acquireIncrement=5jdbc.maxStatements=5jdbc.idleConnectionTestPeriod=60

在部署到生产环境不久后,系统开始出现明显卡顿,高延迟,查看日志发现,项目使用的c3p0连接池出现大量死锁报警
日志信息如下:

06/10 11:04:18 [WARN] com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@407c883 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
06/10 11:04:18 [WARN] com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@407c883 -- APPARENT DEADLOCK!!! Complete Status: Managed Threads: 3Active Threads: 3Active Tasks: com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@3229c1econ thread: C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#2com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@537a86aeon thread: C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#0com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@11203453on thread: C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#1Pending Tasks: com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@594b3dedcom.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@5acec067
Pool thread stack traces:Thread[C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#0,5,main]oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1445)oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:75)oracle.jdbc.driver.OraclePreparedStatementWrapper.close(OraclePreparedStatementWrapper.java:78)com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask.run(GooGooStatementCache.java:934)com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)Thread[C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#1,5,main]oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1445)oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:75)oracle.jdbc.driver.OraclePreparedStatementWrapper.close(OraclePreparedStatementWrapper.java:78)com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask.run(GooGooStatementCache.java:934)com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)Thread[C3P0PooledConnectionPoolManager[identityToken->1bqqnmpaa17atnmt1tzjc2r|14978579]-HelperThread-#2,5,main]oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1445)oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:75)oracle.jdbc.driver.OraclePreparedStatementWrapper.close(OraclePreparedStatementWrapper.java:78)com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask.run(GooGooStatementCache.java:934)com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
 异常堆栈中大概可以看出死锁出现在UncheckedStatementCloseTask,在stackoverflow上看到类似的问题,多是因为由于PrepareStatement缓存问题。项目确实使用了PrepareStatement缓存,但是配置似乎有些问题查看官方文档:

[https://www.mchange.com/projects/c3p0/#configuring_statement_pooling]

maxStatements是JDBC的标准参数,用于控制语句池。maxStatements定义数据源将缓存的PreparedStatements总数。达到此限制时,池将销毁最近最少使用的PreparedStatement。这听起来很简单,但这实际上是一种奇怪的方法,因为从概念上讲,缓存的语句属于各个Connections;它们不是全球资源。为了弄清楚不会“搅动”高速缓存的语句的maxStatements的大小,您需要考虑 应用程序中经常使用的 PreparedStatements 的数量,然后将其乘以池中期望的连接数( 在繁忙的应用程序中为maxPoolSize) 。maxStatementsPerConnection是非标准配置参数,从概念上讲更有意义。它定义允许每个池化Connection拥有多少条语句。您可以将其设置为比应用程序经常 使用的PreparedStatements数量多一些,以避免搅乱。如果这些参数之一大于零,则将启用语句池。如果两个参数都大于零,则将强制执行两个限制。如果只有一个大于零,则将启用语句池,但是将强制执行一个限制。如果statementCacheNumDeferredCloseThreads大于零,则语句池将物理上延迟缓存的语句,直到其任何客户端未在其父连接或该池本身内部(例如在测试中)使用它为止。对于某些JDBC驱动程序(尤其是Oracle),如果使用父连接,则尝试关闭Statement冻结。此参数默认为0。如果观察到“连接关闭”任务上的“ APPARENT DEADLOCKS”,则将其设置为正值。几乎总是该值应该是一个:如果您需要多个专门用于语句销毁的线程,则可能应该将maxStatements和/或 maxStatementsPerConnection设置为更高的值,这样您就不会这么快地浏览缓存的Statements。

大概意思是说参数maxStatements为所有连接加起来最大持有的缓存数,这是JDBC的标准,在c3p0中增加了一个参数maxStatementsPerConnection,是每个连接最大持有的缓存数,这个参数明显更加科学。
项目中配置maxStatements为3,启用语句池,而maxPoolSize为100。。。
也就是说这100个连接最多只能持有3个Statement缓存,导致频繁触发回收,如果此时读取缓存则会发生阻塞,进而引发了APPARENT DEADLOCKS,但如果配置项statementCacheNumDeferredCloseThreads大于零,则语句池会推迟语句缓存清除,直到该语句不被任何连接使用为止。
解决方案1:关闭语句池,把maxStatements,maxStatementsPerConnection设置为0。查看日志没有再出现死锁,但系统响应时间明显增加。
解决方案2:增加语句池最大容量maxStatementsPerConnection,并且开启statementCacheNumDeferredCloseThreads,maxStatementsPerConnection应根据应用所用到的语句进行估算,statementCacheNumDeferredCloseThreads值设置为1即可。

记录一个c3po连接池APPARENT DEADLOCK解决方法相关推荐

  1. 一个Fluent动网格问题及解决方法的记录

    一个Fluent动网格问题及解决方法的记录 case中有固体和液体两种区域.由于固体模仿的是推进剂非均匀燃烧,因此燃面上下两侧边界层外有一部分使用了三角形网格.在计算过程中,推进剂的下部和右侧均是流场 ...

  2. SQLyong连接mysql 2058错误解决方法(记录)

    docker sqlyong连接mysql 2058错误解决方法 原因 出现错误的主要原因是mysql 8以上的版本的加密方式发生了改变,导致连接失败 解决方法 1.docker进入mysql容器 d ...

  3. win7计算机无法远程访问,win7无法被远程桌面连接的几种解决方法

    有时候由于工作需要会开启远程桌面,远程连接好友的电脑,但是有的时候会发生win7无法被远程桌面连接的情况,有可能是win7电脑设置过程中出错或者是遗漏了什么没有设置,也有可能是设置完全正确.如果 wi ...

  4. 基于ODBC的MFC与sql_server2008r2连接教程和错误解决方法

    基于ODBC的MFC与sql_server2008r2连接教程和错误解决方法 应用环境: 编译平台:vs2013 数据库:Mysql Server2008r2 桥接软件: ODBC(微软提供的开放数据 ...

  5. win10蓝牙已配对连接不上_Win10系统蓝牙配对手机连接不成功的解决方法

    Win10系统蓝牙配对手机连接不成功的解决方法.很多的Win10用户都在使用蓝牙连接手机,一些网友在连接时出现win10系统蓝牙已配对但连接不成功,出现在这样的问题怎么解决呢?下面我们来看看Win10 ...

  6. 网络连接的常见问题和解决方法

    网络连接常见错误和解决方法,整合网上资源,仅供参考. 1.宽带连接错误691(由于域上的用户名或密码无效而拒绝访问)和错误635(未知错误) (1).出现错误691的原因 <1>.域上名出 ...

  7. 阿里云国际版无法远程连接Windows服务器的解决方法

    免责声明:本文档可能包含第三方产品信息,该信息仅供参考.阿里云对第三方产品的性能.可靠性以及操作可能带来的潜在影响,不做任何暗示或其他形式的承诺. 概述 下面来和87cloud一起了解阿里云国际版无法 ...

  8. php5.3无法加载mysql数据库模块_PHP_php5.3不能连接mssql数据库的解决方法,本文实例讲述了php5.3不能连接m - phpStudy...

    php5.3不能连接mssql数据库的解决方法 本文实例讲述了php5.3不能连接mssql数据库的解决方法.分享给大家供大家参考.具体分析如下: 自从php5.3之后系统就不支持mssql_conn ...

  9. mysql创建连接失败怎么办,MYSQL在Windows 2003上连接不上的解决方法

    MYSQL在Windows 2003上连接不上的解决方法 今天搭建mysql数据库,连接了半天,都提示10061错误,以为密码出了问题试了半天,压根连服务都连接不上,忙活了半个多小时,才发现是系统补丁 ...

最新文章

  1. 用telnet命令,POP3接收邮件
  2. Codechef Coders’Legacy 2018 CLSUMG Sum of Primes
  3. redis延迟队列 如何确保成功消费_千万级延时任务队列如何实现,看美图开源的-LMSTFY...
  4. 大数据使用及现状调研报告
  5. 这些全国各地甜点,你都吃过了吗?
  6. HH SaaS电商系统的销售订单毛利润模块设计
  7. Java 集合框架(List、Set、Map、Iterator、Stack、Properties)
  8. 信息学奥赛一本通(1106:年龄与疾病)
  9. Atitit  从 RGB 到 HSL 或 HSV 的转换
  10. 【java】 获取计算机信息及Java信息
  11. web前端新手最容易出现的4个错误,你有出错过吗?
  12. python迅雷下载任务出错_Celery提交任务出错?
  13. 手机最快的网络服务器,手机网速最快的dns地址
  14. Acme CAD Converter 的线宽要怎么设置啊
  15. 329 矩阵中的最长递增路径
  16. Mac电脑C语言开发的入门帖
  17. [C#]Unicode与汉字互转
  18. Echarts 绘制单独省份地图
  19. 内蒙古大学计算机考研复试分数线,内蒙古大学2016年考研复试分数线
  20. An error occurred uploading to the App Store.

热门文章

  1. 最长回文子串(C/C++动态规划)
  2. Linux命令和实例大全
  3. java 定时任务只执行一次_Java执行定时任务
  4. 谋定农民丰收节交易会-李加映:功能性农业·农业大健康大会
  5. rebar3使用介绍(七)测试
  6. UnionID获取途径
  7. 寝室环境对大学生睡眠的影响调查
  8. MySQL快速生成100W条测试数据
  9. EMC设计的3大规律和3大要素
  10. 开漏输出、推挽输出的区别