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断掉的时候会很久才会被发现。

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Hive是一个基于Hadoop的数据仓库基础结构,它提供了SQL查询和数据分析功能。Hive的代码阅读是指对Hive项目的代码进行逐行分析和理解,以深入了解Hive的内部工作原理和实现细节。 Hive的代码阅读可以从导读开始。导读部分是Hive代码仓库中的一些重要文档和指南,它们提供了关于Hive项目的概述和指导。 首先,我们可以阅读Hive项目的README文件。该文件通常包含了对项目的介绍、功能特点和使用说明。README文件一般会介绍Hive的目标、核心组件和HiveQL查询语言等内容,为我们提供了整体了解Hive的入口。 接下来,我们可以查看Hive项目中的文档目录。在这个目录下,我们可以找到各种文档、指南和设计文档,它们详细描述了Hive的不同方面和内部机制。这些文档可以帮助我们了解Hive的体系结构、数据处理流程、优化技巧等内容,为后续阅读代码提供了必要的背景知识。 此外,还可以关注Hive项目的WIKI页面。Hive的WIKI页面常常有丰富的内容,包括开发指南、常见问题解答等。这些页面中提供了一些较为具体和实用的信息,可以帮助我们更好地理解Hive的代码。 在阅读Hive代码时,我们应该注重核心模块和关键类的分析。可以从查询解析器、查询优化器和执行引擎等模块开始阅读。这些模块负责将HiveQL查询转化为Hadoop任务并执行查询操作。 最后,我们还可以参考Hive代码中的注释和代码文档。良好的代码注释可以帮助我们理解代码的意图和实现细节,而代码文档则可以提供更加详细的说明和使用方法。 综上所述,Hive阅读的导读包括了阅读README文件、查看文档目录和WIKI页面、重点关注核心模块和关键类的分析,以及参考代码注释和文档等内容。通过导读,我们可以为接下来的阅读做好准备,更好地理解Hive的工作原理和实现方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zyc_2754

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值