数据库连接池之c3p0-0.9.1.2,线上偶发APPARENT DEADLOCK,如何解?

本文探讨了c3p0连接池在使用中遇到的线上偶发APPARENT DEADLOCK问题。文章分析了连接的归还过程,特别是`connection.close()`方法的逻辑,并详细介绍了涉及的线程池任务类型,如AcquireTask、DestroyResourceTask等,以及可能导致阻塞的原因。通过对线程池执行task的机制解析,试图找出问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本篇其实是承接前面两篇的,都是讲定位线上的c3p0数据库连接池,发生连接泄露的问题。

第二篇讲到,可以配置两个参数,来找出是哪里的代码借了连接后没有归还。但是,在我这边的情况是,对于没有归还的连接,借用者的堆栈确实是打印到日志了,但是我在本地模拟的时候,发现其实这些场景是有归还连接的,所以,我开始怀疑不是代码问题。

不是业务代码问题,能是啥问题呢?我们先来看看连接是怎么归还到连接池的。

连接的实际类型

我在本地debug了下,发现获取连接时,代码如下:

com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource#getConnection()
public Connection getConnection() throws SQLException
{
    // javax.sql.PooledConnection,实际类型为com.mchange.v2.c3p0.impl.NewPooledConnection
    PooledConnection pc = getPoolManager().getPool().checkoutPooledConnection();
    return pc.getConnection();
}

说实话,之前都没注意到jdbc api里还有javax.sql.PooledConnection这个类,这里,就是首先从c3p0连接池获取了一个com.mchange.v2.c3p0.impl.NewPooledConnection对象,然后转换为javax.sql.PooledConnection

image-20230717165723827

然后,调用javax.sql.PooledConnection#getConnection,会返回给实际类型为com.mchange.v2.c3p0.impl.NewProxyConnection的对象。

com.mchange.v2.c3p0.impl.NewPooledConnection#getConnection
public synchronized Connection getConnection() throws SQLException
{
    if ( exposedProxy == null )
    {
        exposedProxy = new NewProxyConnection( physicalConnection, this );
    }
    return exposedProxy;
}

image-20230717170019168

在该类中,主要包含如下几个字段:

image-20230717170256849

inner:实际的底层连接,如我这里,其类型为oracle.jdbc.driver.T4CConnection
parentPooledConnection:javax.sql.PooledConnection类型的池化连接
cel:类型为ConnectionEventListener,就是一个监听器

connection.close方法逻辑

com.mchange.v2.c3p0.impl.NewProxyConnection
public synchronized void close() throws SQLException {
    // 0
    if (!this.isDetached()) {
        // 1 
        NewPooledConnection npc = this.parentPooledConnection;
        this.detach();
        // 2
        npc.markClosedProxyConnection(this, this.txn_known_resolved);
        this.inner = null;
    }  
}

0处,检查该对象是否已经和底层的池化连接解绑:

boolean isDetached() {
    return this.parentPooledConnection == null;
}

1处,通过parentPooledCon

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值