https://my.oschina.net/haogrgr/blog/224010
今天在一台配置很低的機器上運行批量更新的程序~~~
大概跑了三十分鍾~~~這配置~~~這程序~~~
然后華麗麗的報異常了~~~
具體異常是這樣的,
DEBUG: (BaseJdbcLogger.java:132) ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4d4e22e1] [2014-07-17 15:19:35]5363945354 [Druid-ConnectionPool-Destory-1422598563] com.alibaba.druid.pool.DruidDataSource:1132 WARN : (DruidDataSource.java:1132) get/close not same thread ERROR: (DruidDataSource.java:1815) abandon connection, open stackTrace at java.lang.Thread.getStackTrace(Thread.java:1588) at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:942) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4534) at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:661) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4530) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:880) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:872) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:97)
這個是最初的異常, 后面還有一大批異常,
Caused by: java.sql.SQLException: connection holder is null at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1085) at com.alibaba.druid.pool.DruidPooledConnection.getMetaData(DruidPooledConnection.java:825) at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:285) ... 70 more
說什么holder為空
第一眼看到holder就像到Spring的源碼, 里面到處是holder(笑)
但是這里的holder不是Spirng里面的,是Druid的
這個holder大概是用來hou住連接池里面的連接的.
然后為什么為空了呢? 目測是哪個鏈接壞了, 或者被意外的關閉了...
根據異常調源碼 at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:942)
941 if (isRemoveAbandoned()) { 942 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 943 poolalbeConnection.setConnectStackTrace(stackTrace); poolalbeConnection.setConnectedTimeNano(); poolalbeConnection.setTraceEnable(true); synchronized (activeConnections) { activeConnections.put(poolalbeConnection, PRESENT); } }
看不出啥來. 只能將日志繼續看看, 還是看不出啥來
然后看了上面代碼幾遍后, 老覺得 isRemoveAbandoned() 這個方法有鬼.
查看調用處,:
恩, 這個DestroyConnectionThread非常可疑, 跳
if (isRemoveAbandoned()) { removeAbandoned(); }
繼續
public int removeAbandoned() { int removeCount = 0; long currrentNanos = System.nanoTime(); List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>(); synchronized (activeConnections) { Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator(); for (; iter.hasNext();) { DruidPooledConnection pooledConnection = iter.next(); if (pooledConnection.isRunning()) { continue; } long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000); if (timeMillis >= removeAbandonedTimeoutMillis) { iter.remove(); pooledConnection.setTraceEnable(false); abandonedList.add(pooledConnection); } } } ....略 }
擦, 這里不對頭, timeMillis >= removeAbandonedTimeoutMillis timeMillis 這個是getConnection()被調用時的時間
意思就是一個連接被get后, 超過了 removeAbandonedTimeoutMillis這么久我就弄死你.
然后繼續找removeAbandonedTimeoutMillis 這玩意在哪里設置的 ,最后發現是在
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="1800" />
初始化配置的這里設置的, 這兩個參數的大概意思就是,
通過datasource.getConnontion() 取得的連接必須在removeAbandonedTimeout這么多秒內調用close(),要不我就弄死你.(就是conn不能超過指定的租期)
然后調成2個小時~~~
然后程序成功跑完~~~華麗麗的等了50分鍾
總結:
連接池為了防止程序從池里取得連接后忘記歸還的情況, 而提供了一些參數來設置一個租期, 使用這個可以在一定程度上防止連接泄漏
但是如果你的業務真要跑這么久~~~~那還是注意下這個設置.