数据库连接泄漏诊断

1 背景

如果将mybatis guice 事务代理切面 中的endTransaction注释掉,那么将会有连接泄漏,本文是一个实践

private void endTransactionReal() {
//getOdsSqlSessionManager().close();
}

2

2.1 连接池信息

初始:4

最大:10

2.2 取得连接的过程

org.apache.commons.dbcp.BasicDatasource.getConnection

org.apache.commons.dbcp.BasicDatasource.createDataSource

org.apache.commons.dbcp.PoolingDatasource.getConnection

org.apache.commons.pool.impl.GenericObjectPool.borrowObject

2.3 归还连接的过程

org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close

org.apache.commons.dbcp.PoolableConnection.close

org.apache.commons.pool.impl.GenericObjectPool.returnObject

3 服务器启动后

借用一次netstat && oracle 连接检测乌龙  的方式检测初始oracle连接

$ netstat -ano|grep ip

TCP localinstanceip:49413 oracleip:1568 TIME_WAIT 0
TCP localinstanceip:54128 oracleip:1567 ESTABLISHED 18612
TCP localinstanceip:54130 oracleip:1567 ESTABLISHED 18612
TCP localinstanceip:54132 oracleip:1568 ESTABLISHED 18612
TCP localinstanceip:60356 oracleip:1568 ESTABLISHED 18612

请注意,由于使用了懒加载,所以首次打开页面之前没有这些连接,后才有

可以看到4条establish

 4 和 5 两种情况都是这个结果

4 no endtransaction

4.1 4次访问后(含首次激活懒加载的那个第一次)

仍然显示4条连接

4.2 第5次访问后

出现5条连接,证明连接没有归还,导致连接池新开了连接

4.3 第6-第10次访问

断点调试调用链:

org.apache.commons.dbcp.PoolingDatasource.getConnection

org.apache.commons.pool.impl.GenericObjectPool.borrowObject

commit

end

org.apache.commons.dbcp.PoolableConnection.close

org.apache.commons.pool.impl.GenericObjectPool.returnObject  注意没有这两条

结果显示10条连接

4.4 第11次刷新页面,页面阻塞

 jstack

可以看到有一条业务线程,(使用scef项目名ctrl F)

"GUI-Thread-43, TaskID:825, Start Time:07-09 04:26:28" #145 prio=10 os_prio=2 tid=0x00000000277fa800 nid=0x5bec in Object.wait() [0x000000007324c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118)
- locked <0x000000078093e458> (a org.apache.commons.pool.impl.GenericObjectPool$Latch)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at com.citi.risk.core.data.db.provider.impl.LazyDataSource.getConnection(LazyDataSource.java:124)
at org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:140)
at org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection(JdbcTransaction.java:62)
at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:315)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:75)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:61)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:303)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:154)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:102)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:82)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113)
at sun.reflect.GeneratedMethodAccessor317.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.session.SqlSessionManager$SqlSessionInterceptor.invoke(SqlSessionManager.java:334)
at com.sun.proxy.$Proxy179.selectList(Unknown Source)
at org.apache.ibatis.session.SqlSessionManager.selectList(SqlSessionManager.java:190)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:122)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:64)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
at com.sun.proxy.$Proxy325.queryUserByLikeId(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

阻塞

5 has endtransaction

重复4的步骤

5.1 第5次访问开始后若干次,仍然显示4条连接

5.2 调用链

org.apache.commons.dbcp.PoolingDatasource.getConnection

org.apache.commons.pool.impl.GenericObjectPool.borrowObject

commit

end

org.apache.commons.dbcp.PoolableConnection.close

org.apache.commons.pool.impl.GenericObjectPool.returnObject

原文地址:https://www.cnblogs.com/silyvin/p/14991026.html