1、设置
removeAbandoned 参数默认为 false,可以通过 DruidDataSource.setRemoveAbandoned(true)开启
2、含义
防止连接泄露,在一个连接长时间未被关闭时,会主动回收该连接,默认关闭,官方不推荐在生产环境开启。
3、工作原理
查看关于 removeAbandoned 的相关测试案例 TestRemoveAbandoned:
protected void setUp() throws Exception {
driver = new MockDriver();
dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mock:xxx");
dataSource.setDriver(driver);
dataSource.setInitialSize(1);
dataSource.setMaxActive(2);
dataSource.setMaxIdle(2);
dataSource.setMinIdle(1);
dataSource.setMinEvictableIdleTimeMillis(300 * 1000); // 300 / 10
dataSource.setTimeBetweenEvictionRunsMillis(10); // 180 / 10
dataSource.setRemoveAbandoned(true);
dataSource.setRemoveAbandonedTimeoutMillis(10);
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setValidationQuery("SELECT 1");
dataSource.setFilters("stat");
dataSource.setLogAbandoned(true);
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
}
public void test_removeAbandoned() throws Exception {
Connection conn = dataSource.getConnection();
Assert.assertEquals(1, dataSource.getActiveCount());
Assert.assertEquals(0, dataSource.getPoolingCount());
// 超时之后,连接自动关闭
Thread.sleep(100);
Assert.assertTrue(conn.isClosed());
Assert.assertEquals(1, dataSource.getRemoveAbandonedCount());
Assert.assertEquals(0, dataSource.getActiveCount());
Assert.assertEquals(1, dataSource.getPoolingCount());
}
复制代码
从测试案例中可以发现,设置了 removeAbandoned 后,如果只获取连接,但是不主动关闭的话,就可以触发 Druid 的主动关闭连接的机制。
我们全局搜索一下 removeAbandoned,发现主要有这几个地方调用了这个参数:
1、建立连接时,如果开启了这个参数,会记录调用线程栈,并把这个连接放入 activeConnections 这个 map 中;
2、在连接使用前将当前连接 running 参数置为 true;
3、在连接使用后记录当前时间到 lastActiveTimeMillis,将 running 参数置为 false;
4、在 DestroyTask 线程中检查连接是否长时间未被关闭,如果是的话就关闭连接,整个过程需要加锁;
//连接是否使用状态
if (pooledConnection.isRunning()) {
continue;
}
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);
//连接空闲时间大于设置的参数removeAbandonedTimeoutMillis,关闭连接
if (timeMillis >= removeAbandonedTimeoutMillis) {
iter.remove();
pooledConnection.setTraceEnable(false);
abandonedList.add(pooledConnection);
}
复制代码
5、在关闭连接的时候通过判断 removeAbandoned 决定是否要使用锁保证线程安全,因为开始 removeAbandoned 后,一个连接可能会被使用连接的线程关闭,也可能会被 DestroyTask 线程关闭,加锁保证线程安全。
4、总结
通过上面的分析,我们发现,以上在开启 removeAbandoned 后,很多对连接的操作就要增加锁来保证线程安全性,用效率换取了线程的安全性。而且现在的大多数框架都会保证连接在使用后得到释放,这个参数就没有打开的必要了,所以官方才不推荐生产环境打开这个参数。
评论