DruidCP源码阅读6 -- testOnBorrow、testOnReturn、testOnWhile参数分析

1、testOnBorrow分析

参数定义:testOnBorrow:获取连接时检测,即每次使用连接时都会测试当前连接是否可用,开启后对性能有些影响,官方不建议开启false

if判断中如果配置了filters那么走责任链否则进行getConnectionDirect

    public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
        // 在初始化dataSource时并不会执行init,而是在第一次获取连接的时候进行init
        init();

        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(this);
            return filterChain.dataSource_connect(this, maxWaitMillis);
        } else {
            return getConnectionDirect(maxWaitMillis);
        }
    }

进入getConnectionDirect

//testOnBorrow:获取连接时检测,即每次使用连接时都会测试当前连接是否可用,开启后对性能有些影响,官方不建议开启false
if (testOnBorrow) {
    boolean validate = 
        testConnectionInternal(poolableConnection.holder,poolableConnection.conn);
    if (!validate) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("skip not validate connection.");
        }

    discardConnection(poolableConnection.holder);
        continue;
    }
}

2、testOnReturn分析

参数定义:testOnReturn:连接放回连接池时检测,同testOnBorrow影响性能,官方不建议开启false

回收连接时进行连接的可用性分析

/**
     * 回收连接
     */
    protected void recycle(DruidPooledConnection pooledConnection) throws SQLException {
        。。。
            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;
                }
            }
           。。。
    }

回收连接不是本次的重点,下次重点分析回收连接过程!

3、testWhileIdle分析 --- 重点!!!

参数定义:testWhileIdle:空闲时检测,testOnBorrow为false时,会进行testWhileIdle检查,testWhileIdle默认也是true,即不在每次都检测连接是否可用,而是空闲时间检测,官方建议开启true

进入getConnectionDirect

/*
                testOnBorrow:获取连接时检测,即每次使用连接时都会测试当前连接是否可用,开启后对性能有些影响,官方不建议开启false
             */
            if (testOnBorrow) {
                boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
                if (!validate) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("skip not validate connection.");
                    }

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

                // 如果没开启testOnBorrow,并且开启了testWhileIdle
                // 空闲时检测,testOnBorrow为false时,会进行testWhileIdle检查,testWhileIdle默认也是true,即不在每次都检测连接是否可用,而是空闲时间检测,官方建议开启true
                if (testWhileIdle) {
                    // 获取上面getConnectionInternal时拿到封装好的连接
                    final DruidConnectionHolder holder = poolableConnection.holder;
                    long currentTimeMillis = System.currentTimeMillis();
                    long lastActiveTimeMillis = holder.lastActiveTimeMillis;
                    long lastExecTimeMillis = holder.lastExecTimeMillis;
                    long lastKeepTimeMillis = holder.lastKeepTimeMillis;

                    // 更新当前连接的最后活跃时间
                    // lastActiveTimeMillis:连接最后活跃时间
                    if (checkExecuteTime
                            && lastExecTimeMillis != lastActiveTimeMillis) {
                        lastActiveTimeMillis = lastExecTimeMillis;
                    }

                    /*
                        lastKeepTimeMillis:连接的上次操作时间
                        lastKeepTimeMillis > lastActiveTimeMillis时,更新连接最后活跃时间为上次活跃时间
                     */
                    if (lastKeepTimeMillis > lastActiveTimeMillis) {
                        lastActiveTimeMillis = lastKeepTimeMillis;
                    }

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

                    /*
                        timeBetweenEvictionRunsMillis:在指定周期内检测连接的有效性,默认1分钟
                     */
                    long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;

                    // 开启了testWhileIdle 但是 timeBetweenEvictionRunsMillis <= 0时,将检测周期配置为1分钟
                    if (timeBetweenEvictionRunsMillis <= 0) {
                        timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
                    }

                    // 开始检测逻辑
                    if (idleMillis >= timeBetweenEvictionRunsMillis
                            || idleMillis < 0 // unexcepted branch
                    ) {
                        boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
                        // 连接无效时,标注当前连接的discard状态为true
                        if (!validate) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("skip not validate connection.");
                            }

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

getConnectionDirect是一个死循环,开启testWhileIdle后,判断如果当前连接超过了上一次的活性检测(默认空闲时间超过1分钟)时,进行活性检测

testWhileIdle与testOnBorrow不同的是,testWhileIdle会判断连接空闲时间大于阈值后再做活性检测,而testOnBorrow是在每次获取连接时都要进行活性检测,所以在并发量打的时候testWhileIdle会保证一定的可用性,而testOnBorrow增加获取连接的时间

总结

在dataSource中有大量的生产者/消费者模式

生产者

empt.await  生产者阻塞
empt.signal 生产者被唤醒,生产连接

消费者

notEmpty.await  消费者等待连接
notEmpty.signal  消费者唤醒,可以去使用连接

在getConnection时会大量使用这种模式进行线程间的切换,大大提升了获取连接的效率;
testWhileIdle是一种空闲时对连接的活性检测机制,在规定时间内最大限度的保证连接的可用性,失效连接及时丢弃,小于midIdle是唤醒生产者去创建连接;

testWhileIdle并不是在空闲的时候去检测连接的活性,而是在短时间内判断一个连接是否可用,因为有时候TCP断掉的时候会很久才会被发现。

在获取连接的时候,判断连接是不是很长时间没有用了,如果没有用了,那么去判断活性判断,在每次获取连接的时候,假如连接被动断掉了,是很长时间才会被发现的,所以这个机制能很快的发现已经断掉的连接。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容