原文鏈接org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool ex
今天同事在測試文件同步功能時,發現當刪除一個文件夾目錄,裏面含有很多文檔的時候就報:
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:103)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
... 154 more
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:756)
at org.apache.commons.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:74)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
... 157 more
2010-3-11 9:34:40 org.apache.catalina.core.ApplicationContext log
信息: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted
[DATAMANAGER] ERROR 2010-03-11 09:34:41,859 [http-8080-2] JDBCExceptionReporter.logExceptions(78) | Cannot get a connection, pool exhausted
[DATAMANAGER] ERROR 2010-03-11 09:34:41,859 [http-8080-2] JDBCExceptionReporter.logExceptions(78) | Cannot get a connection, pool exhausted
org.hibernate.exception.GenericJDBCException: Cannot open connection
......
初看org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted知道是連接池已經耗盡了。
心想不會是在刪除的過程中,定時器已經啓動了建索引進程,由於未控制線程數而導致連接池耗盡?
但是看到同事的測試目錄下文件數也不是很多,全部是圖片,大概也有三四十張。但是建索引也不至於,平時會索引整個數據庫文檔表建索引那時的數量比這裏大多了。
網上一查:
A、Cannot get a connection, pool exhausted解決辦法
轉自:http://chivas2008.blogbus.com/logs/28735149.html
解決的辦法有3個
1重啓你的服務器
2在content.xml中,將maxActive設置爲零,或者調高它的值
3在你的程序中正確關閉connections 這裏有一點要注意要把關閉的語句寫在finally中,如果你寫在try{}中出現異常的話是無法正確關閉的。
要象這樣
} catch (SQLException e) {
/** Exception handling **/
} finally {
try {
if (stmt != null)
stmt.close();
if (dbConnection != null)
dbConnection.close();
} catch (SQLException e) {
/** Exception handling **/
}
}
當然這3個方法裏前兩個並不能從根本上解決你的問題,所以還是要好好研究你的程序,一定要將用完的connection放回到池中。
1 問題描述
Web程序在tomcat剛開始運行時速度很快,但過一段時間後發現速度變得很慢。
檢查日誌輸出,發現異常如下:
org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:
java.util.NoSuchElementException: Timeout waiting for idle object
同時在SQLServer事件探查器中發現,每執行一次sql語句都要產生Audit login事件,語句執行後產生
Audit logout事件。說明每一次tomcat都是重新打開新的連接。
2 問題解決
tomcat 的數據源定義提供了三個參數:
a. 如果設爲true則tomcat自動檢查恢復重新利用,沒有正常關閉的Connection.(默認是false)
<parameter>
<name>removeAbandoned</name>
<value>true</value>
</parameter>
b. 設定連接在多少秒內被認爲是放棄的連接,即可進行恢復利用。
<parameter>
<name>removeAbandonedTimeout</name>
<value>60</value>
</parameter>
c.輸出回收的日誌,可以詳細打印出異常從而發現是在那裏發生了泄漏
<parameter>
<name>logAbandoned</name>
<value>true</value>
</parameter>
B、Timeoutwaitingforidleobject
轉自:http://203.208.37.132/search?q=cache:9TmBcAJrYhQJ:jiangzi87.blog.ccidnet.com/blog.php%3Fdo%3Dshowone%26itemid%3D474468%26typ%3Dblog+java.util.NoSuchElementException:+Timeout+waiting+for+idle+object&cd=5&hl=zh-CN&ct=clnk&gl=cn&st_usg=ALhdy2-dZRxeN0j7d6MJ0Shp7tXcjwyumQ
1、request too large錯誤 在我們應用系統中,有些用戶反映在填寫申請表的時候,有時會出現request too large 的錯誤,導致操作失敗.經查看原因是: 用戶在填寫申請表的時候.我們會擱一定的時間,朝cookies裏保存數據.如果cookies裏數據過大,就會導致request too large 的錯誤,清除cookies,問題就可以解決.. |
看到我對於A中紅色顯示的部分,這個參數對於查找原因真的很重要。初看上面的報錯真得讓我一頭霧水,後來配置上這個參數,再運行控制檯的報錯信息更加明確,從報錯信息中我找到了運行該功能存在兩個地方連接池泄漏問題:
at com.xxx.action.DoccatalogAction.getDocCatalogListByCatCode(DoccatalogAction.java:1178)
at com.xxx.organization.dao.hibernate.UserHibernateDAOBean.getUserByName(UserHibernateDAOBean.java:54)
at com.xxx.doc.desktopapp.action.DesktopAppAction.removeAllDataByCategoryList(DesktopAppAction.java:564)
從中可以知道是在哪個方法,哪一行的代碼存在連接池泄漏問題。
【原因】:
原來真的是同事寫的代碼中未對session,Connection,Statement等與數據庫相關的連接未釋放。
【解決方法】:
1、對於session的部分全部加上
//避免未釋放連接導致連接池耗盡
Session session = this.getSession();
try{
//執行代碼 ...
}finally{
this.releaseSession(session);
}
2、對於數據庫連接
Session session = listHelper.getSessionFactory().openSession();
Connection cnn = null;
Statement state = null;
ResultSet rs = null;
try{
cnn = session.connection();
state = cnn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
String strSQL="";
strSQL+=" select d.* from tb_datapriv_grant g , tb_datapriv d where g.member_id='"+userid+"' ";
rs = state.executeQuery(strSQL);//查詢目錄用戶是否有權限
......
}finally{
//關閉rs
if(null!=rs){
rs.close();
rs = null;
}
//關閉state
if(null!=state){
state.close();
state = null;
}
//關閉cnn
if(null!=cnn){
cnn.close();
cnn = null;
}
//關閉session
if(null!=session){
session.close();
session = null;
}
}
當然,可能你的項目裏獲取session和釋放session的方法和我的並不一樣,因爲有的類方法是我們封裝好的。但是相同的是一定要記得釋放。