1、简介
在本文中,我们将测试 Druid 连接池配置参数 testWhileIdle 的作用。
2、环境
os-window10
druid-1.2.8
jdk-1.8.0_312
maven-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、源码如下:
评论