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 后,很多对连接的操作就要增加锁来保证线程安全性,用效率换取了线程的安全性。而且现在的大多数框架都会保证连接在使用后得到释放,这个参数就没有打开的必要了,所以官方才不推荐生产环境打开这个参数。
评论