DBCP數據庫鏈接失效的解決方法(Io 異常:Connection reset)

網上不少評論說DBCP有不少BUG,可是都沒有指明是什麼BUG,只有一部分人說數據庫若是由於某種緣由斷掉後再DBCP取道的鏈接都是失效的鏈接,而沒有從新取。有的時候會報Io 異常:Connection reset。

解決方法: spring

spring中datasource的配置以下:
    <bean id="dispatchdataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> 
    <property name="url" value="jdbc:oracle:thin:@127.0.0.1 :1521:myserver" /> 
    <property name="username" value="user1" /> 
    <property name="password" value="pwd" /> 
    <property name="maxActive" value="10000" /> 
    <property name="maxIdle" value="30" /> 
     <property name="minIdle" value="2" /> 
    <property name="maxWait" value="600000" /> 
    <property name="testOnBorrow" value="true"/> 
    <property name="testWhileIdle" value="true"/> 
    <property name="validationQuery" value="select 1 from dual"/> 
</bean>
sql

分析: 數據庫

DBCP使用apache的對象池ObjectPool做爲鏈接池的實現,有如下主要的方法 apache

Object borrowObject() throws Exception;從對象池取得一個有效對象 oracle

void returnObject(Object obj) throws Exception;使用完的對象放回對象池 url

void invalidateObject(Object obj) throws Exception;使對象失效 spa

void addObject() throws Exception;生成一個新對象 .net


ObjectPool的一個實現就是GenericObjectPool,這個類使用對象工廠PoolableObjectFactory實現對象的生成,失效檢查等等功能,以其實現數據庫鏈接工廠PoolableConnectionFactory作以說明,主要方法: 線程

     Object makeObject() throws Exception; 使用ConnectionFactory生成新鏈接 server

     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語句執行經過就能夠了。

相關文章
相關標籤/搜索