表观死锁 c3p0 0.9.5.1 spring
APPARENT DEADLOCK c3p0 0.9.5.1 spring
我们在使用 c3p0 0.9.5.1(这是 c3p0 的最新版本)时面临明显的死锁。以下是我们正在使用的连接池配置。
p:driverClass="${app.jdbc.driverClassReplica}"
p:jdbcUrl="jdbc:mysql://database,database/dbname"
p:acquireIncrement="5"
p:idleConnectionTestPeriod="300"
p:maxPoolSize="100"
p:maxStatements="2000"
p:minPoolSize="10"
p:maxIdleTime="1800"
p:maxConnectionAge="3600"
p:maxIdleTimeExcessConnections="20"
p:numHelperThreads="15"
p:preferredTestQuery="SELECT 1"/>
以下是日志
ThreadPoolAsynchronousRunner:743---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! #]
2015-06-20 11:36:15 WARN ThreadPoolAsynchronousRunner:759---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Complete Status:
Managed Threads: 15
Active Threads: 15
Active Tasks:
每个活动任务看起来像
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@4ec69595
on thread: C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6
待处理任务:
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@2b131ea8
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@7441bdaf
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@80c67ca
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@667202e6
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@471c7e95
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@1fba8cac
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@1069807a
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@7e71d200
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@62923eda
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@6f5c8cc4
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@251dd0fa
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@4882e01f
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@848386a
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@3d6fbb65
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@72780365
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@25271699
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@293ca9dd
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@4db40151
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@64c294b1
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@22b02425
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@5a150aed
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@1b807bcf
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@10406124
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@72a98ad1
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@58d8da26
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@2a013697
com.mchange.v2.c3p0.stmt.GooGooStatementCacheStmtAcquireTask@35a7090c
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@69430e58
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@3162e965
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@54c8ff37
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@57eb9f5d
池线程堆栈跟踪:
所有 15 个线程看起来如下
Thread[C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6,5,main]
com.mysql.jdbc.StatementImpl.close(StatementImpl.java:575)
com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask.run(GooGooStatementCache.java:938)
每当发生这种情况时,数据库都会在一段时间内无响应,并且数据库的连接数会增加。这是 c3p0 的问题吗?切换到其他 jdbc 池(如 hikaricp 或 boncecp)会有帮助吗?
您遇到的问题与语句缓存有关。切换到其他不缓存语句的池可能会有所帮助。但是通过将 maxStatements
设置为 0 来关闭 c3p0 中的语句缓存将以完全相同的方式提供帮助。如果您不缓存语句,则不必担心语句缓存中的死锁。但也许您喜欢语句缓存带来的性能提升。
幸运的是,如果需要,您可以保留语句缓存的性能优势,而无需迁移到其他池。
问题是某些 DBMS/JDBC 驱动程序无法处理在其父连接正在使用的同时关闭的语句。形式上,这应该没问题,但实际上对于某些 JDBC 驱动程序而言并非如此。当语句缓存试图使父连接恰好正在使用中的语句过期时,对 close()
的调用会发生死锁,最终使线程池饱和并冻结。
c3p0 包含针对这些脆弱驱动程序的解决方法。
将 c3p0 配置参数 statementCacheNumDeferredCloseThreads 设置为 1,c3p0 将神经质地跟踪到期语句的父级是否正在使用,并推迟 close()
调用,直到它未被使用。希望此设置可以解决您的问题。
我猜你的 Spring XML 配置应该是这样的
p:statementCacheNumDeferredCloseThreads="1"
希望对您有所帮助!
我们在使用 c3p0 0.9.5.1(这是 c3p0 的最新版本)时面临明显的死锁。以下是我们正在使用的连接池配置。
p:driverClass="${app.jdbc.driverClassReplica}"
p:jdbcUrl="jdbc:mysql://database,database/dbname"
p:acquireIncrement="5"
p:idleConnectionTestPeriod="300"
p:maxPoolSize="100"
p:maxStatements="2000"
p:minPoolSize="10"
p:maxIdleTime="1800"
p:maxConnectionAge="3600"
p:maxIdleTimeExcessConnections="20"
p:numHelperThreads="15"
p:preferredTestQuery="SELECT 1"/>
以下是日志
ThreadPoolAsynchronousRunner:743---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! #]
2015-06-20 11:36:15 WARN ThreadPoolAsynchronousRunner:759---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Complete Status:
Managed Threads: 15
Active Threads: 15
Active Tasks:
每个活动任务看起来像
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@4ec69595
on thread: C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6
待处理任务:
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@2b131ea8
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@7441bdaf
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@80c67ca
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@667202e6
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@471c7e95
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@1fba8cac
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@1069807a
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@7e71d200
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@62923eda
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@6f5c8cc4
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@251dd0fa
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@4882e01f
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@848386a
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@3d6fbb65
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@72780365
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@25271699
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@293ca9dd
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@4db40151
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@64c294b1
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@22b02425
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@5a150aed
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@1b807bcf
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@10406124
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@72a98ad1
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@58d8da26
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@2a013697
com.mchange.v2.c3p0.stmt.GooGooStatementCacheStmtAcquireTask@35a7090c
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@69430e58
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@3162e965
com.mchange.v2.resourcepool.BasicResourcePoolRefurbishCheckinResourceTask@54c8ff37
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask@57eb9f5d
池线程堆栈跟踪: 所有 15 个线程看起来如下
Thread[C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6,5,main]
com.mysql.jdbc.StatementImpl.close(StatementImpl.java:575)
com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManagerUncheckedStatementCloseTask.run(GooGooStatementCache.java:938)
每当发生这种情况时,数据库都会在一段时间内无响应,并且数据库的连接数会增加。这是 c3p0 的问题吗?切换到其他 jdbc 池(如 hikaricp 或 boncecp)会有帮助吗?
您遇到的问题与语句缓存有关。切换到其他不缓存语句的池可能会有所帮助。但是通过将 maxStatements
设置为 0 来关闭 c3p0 中的语句缓存将以完全相同的方式提供帮助。如果您不缓存语句,则不必担心语句缓存中的死锁。但也许您喜欢语句缓存带来的性能提升。
幸运的是,如果需要,您可以保留语句缓存的性能优势,而无需迁移到其他池。
问题是某些 DBMS/JDBC 驱动程序无法处理在其父连接正在使用的同时关闭的语句。形式上,这应该没问题,但实际上对于某些 JDBC 驱动程序而言并非如此。当语句缓存试图使父连接恰好正在使用中的语句过期时,对 close()
的调用会发生死锁,最终使线程池饱和并冻结。
c3p0 包含针对这些脆弱驱动程序的解决方法。
将 c3p0 配置参数 statementCacheNumDeferredCloseThreads 设置为 1,c3p0 将神经质地跟踪到期语句的父级是否正在使用,并推迟 close()
调用,直到它未被使用。希望此设置可以解决您的问题。
我猜你的 Spring XML 配置应该是这样的
p:statementCacheNumDeferredCloseThreads="1"
希望对您有所帮助!