写点什么

数据库连接池 -Druid 源码学习(七)

作者:wjchenge
  • 2022 年 5 月 17 日
  • 本文字数:1670 字

    阅读完需:约 5 分钟

1、简介

在本文中,我们将测试 Druid 连接池配置参数 testWhileIdle 的作用。

2、环境

os-window10druid-1.2.8jdk-1.8.0_312maven-3.8.1
复制代码


3、配置 testWhileIdle 运行效果

3.1、启动测试类

DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://ip:port");dataSource.setUsername("name");dataSource.setPassword("password");dataSource.setTestWhileIdle(true);dataSource.setValidationQuery("select 'x'");
while (true) { try (DruidPooledConnection connection = dataSource.getConnection()) { System.out.println("获取到连接 = " + connection); } finally { TimeUnit.SECONDS.sleep(5); }}
复制代码

3.2、打印 1 次 获取到连接 = xxx 后断开电脑网络,系统休眠 5 秒后,还能在连接池中拿到连接。

3.3、将 sleep 时间修改为 61 秒之后,在重复 3.2 的步骤,系统在连接池中拿到连接会进行可用性验证。


3.4、以上问题的源码分析

if (testWhileIdle) {  final DruidConnectionHolder holder = poolableConnection.holder;  long currentTimeMillis             = System.currentTimeMillis();  long lastActiveTimeMillis          = holder.lastActiveTimeMillis;  long lastExecTimeMillis            = holder.lastExecTimeMillis;  long lastKeepTimeMillis            = holder.lastKeepTimeMillis;
if (checkExecuteTime && lastExecTimeMillis != lastActiveTimeMillis) { lastActiveTimeMillis = lastExecTimeMillis; }
if (lastKeepTimeMillis > lastActiveTimeMillis) { lastActiveTimeMillis = lastKeepTimeMillis; } // 连接空闲时间 = 当前时间 - 连接最后一次活跃时间 long idleMillis = currentTimeMillis - lastActiveTimeMillis; // 默认 1 分钟 long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis <= 0) { timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; } // 连接空闲时间 >= timeBetweenEvictionRunsMillis(默认1分钟) 才会进行连接的可用性验证操作 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; } }}
复制代码


通过上面的源码可以看到触发连接可用性操作的关键代码是:

idleMillis >= timeBetweenEvictionRunsMillis,由于我们没有设置 timeBetweenEvictionRunsMillis 参数的值,默认 1 分钟,

idleMillis 是通过 currentTimeMillis - lastActiveTimeMillis 得出,每次获取连接的时间间隔 5 秒小于 60 秒,故不触发检查操作,而设置间隔 61 秒则会触发检查操作。

4、同时配置 timeBetweenEvictionRunsMillis

4.1、测试代码如下:

DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://ip:port");dataSource.setUsername("name");dataSource.setPassword("password");dataSource.setTestWhileIdle(true);dataSource.setTimeBetweenEvictionRunsMillis(5 * 1000);dataSource.setValidationQuery("select 'x'");
while (true) { try (DruidPooledConnection connection = dataSource.getConnection()) { System.out.println("获取到连接 = " + connection); } finally { TimeUnit.SECONDS.sleep(5); }}
复制代码

如果设置 timeBetweenEvictionRunsMillis 参数为 5 秒,同时测试每隔 5 秒获取一次连接,则连接池在验证可用性的同时,还把 mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs 的连接进行的丢弃操作,每次连接池返回的都为不同的连接。

4.2、源码如下:


用户头像

wjchenge

关注

还未添加个人签名 2018.07.27 加入

还未添加个人简介

评论

发布
暂无评论
数据库连接池 -Druid 源码学习(七)_Druid_wjchenge_InfoQ写作社区