druid1.0.21版本源码研究之连接回收(分析解决mysql8小时断线)

首先我想说的是,翻遍百度没有一个可用的解决方案,呵呵..我相信实际解决的人不在少数...

大家众所周知,mysql和druid可谓数据库和数据库连接池中的佼佼者...

第一次用mysql用的还是比较头疼的...

尤其是同时碰上druid...简直是要命了..

换过好几次druid版本,完全没有解决...

github上看wenshao说的,maxEvictableIdleTimeMillis用于解决mysql8小时自动中断,从源码看是有效的.

通过源码,总结一下会出现mysql8小时空闲后中断连接可能出现的情况

1.timeBetweenEvictionRunsMillis+minEvictableIdleTimeMillis>8小时

2.minIdle>0,导致druid会至少保留一个连接,使用1.0.18版本及以上版本不会存在该问题,如果你修改了mysql的wait_timeout,那么可以配置maxEvictableIdleTimeMillis判断可空闲最大时间,即使当前线程数等于minIdle也会强制回收,当然这个回收流程需要timeBetweenEvictionRunsMillis间隔时间后才会检测.

如果是其余问题,请查看druid监控页面是否有sql运行导致锁表

而我遇到的连接池挂掉正是mysql锁表导致的,有个sql锁了系统核心的那张表,所以什么操作都无法进行了


回到正题,看看druid如何执行的回收

druid回收的线程

    public class DestroyTask implements Runnable {

        @Override
        public void run() {
            shrink(true);

            if (isRemoveAbandoned()) {
                removeAbandoned();
            }
        }

    }
接下来的代码也很简单易懂,超过各个参数条件设置的一律回收,有些参数api中没有提到,但是同样可以配置.

    public void shrink(boolean checkTime) {
        final List<DruidConnectionHolder> evictList = new ArrayList<DruidConnectionHolder>();//待回收的连接集合
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            return;
        }

        try {
            final int checkCount = poolingCount - minIdle;//连接池连接数-最小保留连接数
            final long currentTimeMillis = System.currentTimeMillis();
            for (int i = 0; i < poolingCount; ++i) {
                DruidConnectionHolder connection = connections[i];

                if (checkTime) {//上一个代码可以看到,传递为true
                    if (phyTimeoutMillis > 0) {
                        long phyConnectTimeMillis = currentTimeMillis - connection.getTimeMillis();//此处直接用当前时间-获取连接的时间
                        if (phyConnectTimeMillis > phyTimeoutMillis) {//连接不管是否空闲,存活phyTimeoutMillis后强制回收
                            evictList.add(connection);
                            continue;
                        }
                    }
                    
                    long idleMillis = currentTimeMillis - connection.getLastActiveTimeMillis();//此处系统时间-该连接最后一次活跃时间,即访问数据库时间
                    
                    if (idleMillis < minEvictableIdleTimeMillis) {//此处是break无问题,空闲连接从0开始排,取从最后开始取
                        break;
                    }
                    
                    if (checkTime && i < checkCount) {//checkTime为true,此处验证上方的最小连接数,释放到最小连接后不再释放
                        evictList.add(connection);
                    } else if (idleMillis > maxEvictableIdleTimeMillis) {//此处验证最大存活时间,无视最小连接数强制回收
                        evictList.add(connection);
                    }
                } else {
                    if (i < checkCount) {
                        evictList.add(connection);
                    } else {
                        break;
                    }
                }
            }

            int removeCount = evictList.size();
            if (removeCount > 0) {//此处重新复制有效连接到连接池数组中
                System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
                Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
                poolingCount -= removeCount;
            }
        } finally {
            lock.unlock();
        }

        for (DruidConnectionHolder item : evictList) {//回收连接
            Connection connection = item.getConnection();
            JdbcUtils.close(connection);
            destroyCount.incrementAndGet();
        }
    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值