【Druid源码阅读】8. 对于连接的管理

11 篇文章 0 订阅

目录

testOnBorrow

testWhileIdle

testOnReturn

结论


第6篇中,分析了如何获取连接,那获取连接后,Druid 是如何管理这些连接的呢?

可以先给结论,是通过几个关键参数来控制的

testOnBorrow
testOnReturn
testWhileIdle

testOnBorrow

首先看 testOnBorrow,从字面理解,是从连接池中获取连接时,要测试连接是否可用。下面是代码中使用这个属性的几处地方:

1179 和 1193 行,是在 validationQueryCheck() 方法中使用的,这个方法是判断是否正确设置了验证连接可用性相关的参数,即如下参数:

testOnBorrow
testOnReturn
testWhileIdle
validConnectionChecker
validationQuery

高亮的 1452 行是个关键,在 DruidDataSource#getConnectionDirect(long maxWaitMillis) 方法中:

if (testOnBorrow) {
    boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
    if (!validate) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("skip not validate connection.");
        }

        discardConnection(poolableConnection.holder);
        continue;
    }
}

可以看到,如果设置了这个参数为 true,就通过 testConnectionInternal 这个方法验证连接是否有效,如果连接无效,通过 discardConnection 方法抛弃连接。

testWhileIdle

下面在看下如果设置为 false 的逻辑,同时里面引出了 testWhileIdle 这个属性(使用空闲时间验证连接可用性)。

} else {
    if (poolableConnection.conn.isClosed()) {
        discardConnection(poolableConnection.holder); // 传入null,避免重复关闭
        continue;
    }

    // 使用空闲时间验证连接可用性
    if (testWhileIdle) {
        final DruidConnectionHolder holder = poolableConnection.holder;
        // 当前时间戳
        long currentTimeMillis             = System.currentTimeMillis();
        // 最近一次使用这个连接的时间戳
        long lastActiveTimeMillis          = holder.lastActiveTimeMillis;
        // 最近一次执行SQL的时间戳
        long lastExecTimeMillis            = holder.lastExecTimeMillis;
        // 最近一次保活时间戳
        long lastKeepTimeMillis            = holder.lastKeepTimeMillis;

        // 如果要检查执行SQL时间,并且执行SQL和使用连接的时间戳不相等时
        if (checkExecuteTime
                && lastExecTimeMillis != lastActiveTimeMillis) {
            // 把最近一次执行SQL时间戳赋值给最近一次使用连接的时间戳
            lastActiveTimeMillis = lastExecTimeMillis;
        }

        // 如果最近一次保活时间戳比最近一次使用连接时间戳更新,赋值
        if (lastKeepTimeMillis > lastActiveTimeMillis) {
            lastActiveTimeMillis = lastKeepTimeMillis;
        }

        // 连接空闲时间
        long idleMillis                    = currentTimeMillis - lastActiveTimeMillis;

        // 剔除连接最小间隔时间
        long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;

        if (timeBetweenEvictionRunsMillis <= 0) {
            // 默认 60s
            timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
        }

        // 空闲时间比剔除最小时间大了
        if (idleMillis >= timeBetweenEvictionRunsMillis
                || idleMillis < 0 // unexcepted branch
                ) {
            boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
            if (!validate) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("skip not validate connection.");
                }

                discardConnection(poolableConnection.holder);
                 continue;
            }
        }
    }
}

通过分析可知,只有这个连接的空闲时间超过了剔除最小时间时,才会对连接进行检测,所以不会像获取或归还连接时就进行测试有性能影响,所以是推荐打开的属性。

testOnReturn

这个属性就是控制在归还连接给连接池时,是否做连接可用测试。

可以看到,在 DruidDataSource 的 1955 行使用了这个属性,为 true 时,对连接进行可用测试,如果已经断开连接了,就关闭连接。

final boolean testOnReturn = this.testOnReturn;

...

if (testOnReturn) {
    boolean validate = testConnectionInternal(holder, physicalConnection);
    if (!validate) {
        JdbcUtils.close(physicalConnection);

        destroyCountUpdater.incrementAndGet(this);

        lock.lock();
        try {
            if (holder.active) {
                activeCount--;
                holder.active = false;
            }
            closeCount++;
        } finally {
            lock.unlock();
        }
        return;
    }
}

以上代码是在如下方法中的:

protected void recycle(DruidPooledConnection pooledConnection) throws SQLException

recycle(DruidPooledConnection) 被调用的地方只有如下方法:

public void recycle() throws SQLException 

 被3个地方调用,可以知道都是在关闭连接时进行的调用。

结论

建议关闭 testOnBorrow 和 testOnReturn,打开 testWhileIdle。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值