關於DBCP斷網數據庫連接失效的解決方案

問題
網上很多評論說DBCP有很多BUG,但是都沒有指明是什麼BUG,只有一部分人說數據庫如果因爲某種原因斷掉後再DBCP取道的連接都是失效的連接,而沒有重新取。就此研讀了一下DBCP的代碼,共享之。
分析
DBCP使用apache的對象池ObjectPool作爲連接池的實現,有以下主要的方法:
1. Object borrowObject() throws Exception;從對象池取得一個有效對象
2. void returnObject(Object obj) throws Exception;使用完的對象放回對象池
3. void invalidateObject(Object obj) throws Exception;使對象失效
4. void addObject() throws Exception;生成一個新對象

ObjectPool的一個實現就是GenericObjectPool,這個類使用對象工廠PoolableObjectFactory實現對象的生成,失效檢查等等功能,以其實現數據庫連接工廠PoolableConnectionFactory做以說明,主要方法:
 Object makeObject() throws Exception; 使用ConnectionFactory生成新連接
 void destroyObject(Object obj) throws Exception;關閉連接
 boolean validateObject(Object obj); 驗證連接是否有效,如果_validationQuery不空,則使用該屬性作爲驗證連接是否有效的sql語句,查詢數據庫
 void activateObject(Object obj) throws Exception;激活連接對象
 void passivateObject(Object obj) throws Exception; 關閉連接生成過的Statement和ResultSet,使連接處於非活動狀態
  而GenericObjectPool有幾個主要屬性
     _timeBetweenEvictionRunsMillis:失效檢查線程運行時間間隔,默認-1
     _maxIdle:對象池中對象最大個數
     _minIdle:對象池中對象最小個數
     _maxActive:可以從對象池中取出的對象最大個數,爲0則表示沒有限制,默認爲8
在構造GenericObjectPool時,會生成一個內嵌類Evictor,實現自Runnable接口。如果_timeBetweenEvictionRunsMillis大於0,每過_timeBetweenEvictionRunsMillis毫秒Evictor會調用evict()方法,檢查對象的閒置時間是否大於 _minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小於等於0時則忽略,默認爲30分鐘),是則銷燬此對象,否則就激活並校驗對象,然後調用ensureMinIdle方法檢查確保池中對象個數不小於_minIdle。在調用returnObject方法把對象放回對象池,首先檢查該對象是否有效,然後調用PoolableObjectFactory 的passivateObject方法使對象處於非活動狀態。再檢查對象池中對象個數是否小於_maxIdle,是則可以把此對象放回對象池,否則銷燬此對象

還有幾個很重要的屬性,_testOnBorrow、_testOnReturn、_testWhileIdle,這些屬性的意義是取得、返回對象和空閒時是否進行驗證,檢查對象是否有效,默認都爲false即不驗證。所以當使用DBCP時,數據庫連接因爲某種原因斷掉後,再從連接池中取得連接又不進行驗證,這時取得的連接實際已經時無效的數據庫連接了。網上很多說DBCP的bug應該都是如此吧,只有把這些屬性設爲true,再提供_validationQuery語句就可以保證數據庫連接始終有效了,oracle數據庫可以使用SELECT COUNT(*) FROM DUAL,不過DBCP要求_validationQuery語句查詢的記錄集必須不爲空,可能這也可以算一個小小的BUG,其實只要_validationQuery語句執行通過就可以了。 

注意事項
所以使用DBCP連接池放必須注意構造GenericObjectPool對象時
     validationQuery:SELECT COUNT(*) FROM DUAL
       _testOnBorrow、_testOnReturn、_testWhileIdle:最好都設爲true
       _minEvictableIdleTimeMillis:大於0 ,進行連接空閒時間判斷,或爲0,對空閒的連接不進行驗證
     _timeBetweenEvictionRunsMillis:失效檢查線程運行時間間隔,如果小於等於0,不會啓動檢查線程
轉自http://blog.csdn.net/sandyen/article/details/723635
發佈了30 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章