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