DBCP連線池原理分析
DBCP連線池介紹
-----------------------------
目前 DBCP 有兩個版本分別是 1.3 和 1.4。
DBCP 1.3 版本需要執行於 JDK 1.4-1.5 ,支援 JDBC 3。
DBCP 1.4 版本需要執行於 JDK 1.6 ,支援 JDBC 4。
1.3和1.4基於同一套原始碼,含有所有的bug修復和新特性。因此在選擇DBCP版本的時候,要看你用的是什麼JDK版本。
DBCP1.2版本效能一般,比c3p0差挺多。DBCP1.4和1.3,配合(依賴)commons pool 1.6的jar包,各方面功能、效能推進到新的高峰。相對1.2版本提高不少。超越(或相當)了c3p0.建議使用DBCP1.4或1.3 + commons pool 1.6
Tomcat7 中保留DBCP連線池,以相容已有應用。並提供了新的Tomcat JDBC pool作為DBCP的可選替代。新出的Tomcat JDBC pool,據說比DBCP 1.4要好,未接觸,也不在本文討論範圍內。
DBCP連線池配置引數講解
-----------------------------
一、Apache官方DBCP文件給出的配置示例:
可參見:http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html
<Context>
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/javatest"/>
</Context>
二、常用引數說明:
可參見:http://elf8848.iteye.com/blog/337981
<Resource
name="jdbc/TestDB" JNDI資料來源的name
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver" JDBC驅動類
url=""
username="" 訪問資料庫使用者名稱
password="" 訪問資料庫的密碼
maxActive="80" 最大活動連線
initialSize="10" 初始化連線
maxIdle="60" 最大空閒連線
minIdle="10" 最小空閒連線
maxWait="3000" 從池中取連線的最大等待時間,單位ms.
validationQuery = "SELECT 1" 驗證使用的SQL語句
testWhileIdle = "true" 指明連線是否被空閒連線回收器(如果有)進行檢驗.如果檢測失敗,則連線將被從池中去除.
testOnBorrow = "false" 借出連線時不要測試,否則很影響效能
timeBetweenEvictionRunsMillis = "30000" 每30秒執行一次空閒連線回收器
minEvictableIdleTimeMillis = "1800000" 池中的連線空閒30分鐘後被回收
numTestsPerEvictionRun="3" 在每次空閒連線回收器執行緒(如果有)執行時檢查的連線數量
removeAbandoned="true" 連線洩漏回收引數,當可用連線數少於3個時才執行
removeAbandonedTimeout="180" 連線洩漏回收引數,180秒,洩露的連線可以被刪除的超時值
/>
DBCP連線池的自我檢測
-----------------------------
預設配置的DBCP連線池,是不對池中的連線做測試的,有時連線已斷開了,但DBCP連線池不知道,還以為連線是好的呢。
應用從池中取出這樣的連線訪問資料庫一定會報錯。這也是好多人不喜歡DBCP的原因。
問題例一:
MySQL8小時問題,Mysql伺服器預設連線的“wait_timeout”是8小時,也就是說一個connection空閒超過8個小時,Mysql將自動斷開該 connection。
但是DBCP連線池並不知道連線已經斷開了,如果程式正巧使用到這個已經斷開的連線,程式就會報錯誤。
問題例二:
以前還使用Sybase資料庫,由於某種原因,資料庫死了後重啟、或斷網後恢復。
等了約10分鐘後,DBCP連線池中的連線還都是不能使用的(斷開的),訪問資料應用一直報錯,最後只能重啟Tomcat問題才解決 。
解決方案:
方案1、定時對連線做測試,測試失敗就關閉連線。
方案2、控制連線的空閒時間達到N分鐘,就關閉連線,(然後可再新建連線)。
以上兩個方案使用任意一個就可以解決以述兩類問題。如果只使用方案2,建議 N <= 5分鐘。連線斷開後最多5分鐘後可恢復。
也可混合使用兩個方案,建議 N = 30分鐘。
下面就是DBCP連線池,同時使用了以上兩個方案的配置配置
validationQuery = "SELECT 1" 驗證連線是否可用,使用的SQL語句
testWhileIdle = "true" 指明連線是否被空閒連線回收器(如果有)進行檢驗.如果檢測失敗,則連線將被從池中去除.
testOnBorrow = "false" 借出連線時不要測試,否則很影響效能
timeBetweenEvictionRunsMillis = "30000" 每30秒執行一次空閒連線回收器
minEvictableIdleTimeMillis = "1800000" 池中的連線空閒30分鐘後被回收,預設值就是30分鐘。
numTestsPerEvictionRun="3" 在每次空閒連線回收器執行緒(如果有)執行時檢查的連線數量,預設值就是3.
解釋:
配置timeBetweenEvictionRunsMillis = "30000"後,每30秒執行一次空閒連線回收器(獨立執行緒)。並每次檢查3個連線,如果連線空閒時間超過30分鐘就銷燬。銷燬連線後,連線數量就少了,如果小於minIdle數量,就新建連線,維護數量不少於minIdle,過行了新老更替。
testWhileIdle = "true" 表示每30秒,取出3條連線,使用validationQuery = "SELECT 1" 中的SQL進行測試 ,測試不成功就銷燬連線。銷燬連線後,連線數量就少了,如果小於minIdle數量,就新建連線。
testOnBorrow = "false" 一定要配置,因為它的預設值是true。false表示每次從連線池中取出連線時,不需要執行validationQuery = "SELECT 1" 中的SQL進行測試。若配置為true,對效能有非常大的影響,效能會下降7-10倍。所在一定要配置為false.
每30秒,取出numTestsPerEvictionRun條連線(本例是3,也是預設值),發出"SELECT 1" SQL語句進行測試 ,測試過的連線不算是“被使用”了,還算是空閒的。連線空閒30分鐘後會被銷燬。
DBCP連線池配置引數注意事項
-----------------------------
maxIdle值與maxActive值應配置的接近。
因為,當連線數超過maxIdle值後,剛剛使用完的連線(剛剛空閒下來)會立即被銷燬。而不是我想要的空閒M秒後再銷燬起一個緩衝作用。這一點DBCP做的可能與你想像的不一樣。
若maxIdle與maxActive相差較大,在高負載的系統中會導致頻繁的建立、銷燬連線,連線數在maxIdle與maxActive間快速頻繁波動,這不是我想要的。
高負載系統的maxIdle值可以設定為與maxActive相同或設定為-1(-1表示不限制),讓連線數量在minIdle與maxIdle間緩衝慢速波動。
timeBetweenEvictionRunsMillis建議設定值
initialSize="5",會在tomcat一啟動時,建立5條連線,效果很理想。
但同時我們還配置了minIdle="10",也就是說,最少要保持10條連線,那現在只有5條連線,哪什麼時候再建立少的5條連線呢?
1、等業務壓力上來了, DBCP就會建立新的連線。
2、配置timeBetweenEvictionRunsMillis=“時間”,DBCP會啟用獨立的工作執行緒定時檢查,補上少的5條連線。銷燬多餘的連線也是同理。
連線銷燬的邏輯
------------------------------
DBCP的連線數會在 0 - minIdle - maxIdle - maxActive 之間變化。變化的邏輯描述如下:
預設未配置initialSize(預設值是0)和timeBetweenEvictionRunsMillis引數時,剛啟動tomcat時,連線數是0。當應用有一個併發訪問資料庫時DBCP建立一個連線。
目前連線數量還未達到minIdle,但DBCP也不自動建立新連線已使數量達到minIdle數量(沒有一個獨立的工作執行緒來檢查和建立)。
隨著應用併發訪問資料庫的增多,連線數也增多,但都與minIdle值無關,很快minIdle被超越,minIdle值一點用都沒有。
直到連線的數量達到maxIdle值,這時的連線都是隻增不減的。 再繼續發展,連線數再增多並超過maxIdle時,使用完的連線(剛剛空閒下來的)會立即關閉,總體連線的數量穩定在maxIdle但不會超過maxIdle。
但活動連線(在使用中的連線)可能數量上瞬間超過maxIdle,但永遠不會超過maxActive。
這時如果應用業務壓力小了,訪問資料庫的併發少了,連線數也不會減少(沒有一個獨立的執行緒來檢查和銷燬),將保持在maxIdle的數量。
預設未配置initialSize(預設值是0),但配置了timeBetweenEvictionRunsMillis=“30000”(30秒)引數時,剛啟動tomcat時,連線數是0。馬上應用有一個併發訪問資料庫時DBCP建立一個連線。
目前連線數量還未達到minIdle,每30秒DBCP的工作執行緒檢查連線數是否少於minIdle數量,若少於就建立新連線直到達到minIdle數量。
隨著應用併發訪問資料庫的增多,連線數也增多,直到達到maxIdle值。這期間每30秒DBCP的工作執行緒檢查連線是否空閒了30分鐘,若是就銷燬。但此時是業務的高峰期,是不會有長達30分鐘的空閒連線的,工作執行緒查了也是白查,但它在工作。到這裡連線數量一直是呈現增長的趨勢。
當連線數再增多超過maxIdle時,使用完的連線(剛剛空閒下來)會立即關閉,總體連線的數量穩定在maxIdle。停止了增長的趨勢。但活動連線(在使用中的連線)可能數量上瞬間超過maxIdle,但永遠不會超過maxActive。
這時如果應用業務壓力小了,訪問資料庫的併發少了,每30秒DBCP的工作執行緒檢查連線(預設每次查3條)是否空閒達到30分鐘(這是預設值),若連線空閒達到30分鐘,就銷燬連線。這時連線數減少了,呈下降趨勢,將從maxIdle走向minIdle。當小於minIdle值時,則DBCP建立新連線已使數量穩定在minIdle,並進行著新老更替。
配置initialSize=“10”時,tomcat一啟動就建立10條連線。其它同上。
minIdle要與timeBetweenEvictionRunsMillis配合使用才有用,單獨使用minIdle不會起作用。
Tomcat中配置DBCP連線池
-----------------------------
Tomcat自帶DBCP的包,是$CATALINA_HOME/lib/tomcat-dbcp.jar。
tomcat-dbcp.jar含有commons pool、commons DBCP兩個包的內容。但只含有與連線池有關的類。
資料來源配置在context.xml檔案中, 要在tomcat的lib目錄中放jdbc 驅動包
資料來源配置在server.xml的host中,不需要在tomcat的lib目錄中放jdbc 驅動包,只使用工程中的jdbc驅動包
JNDI配置:更改tomcat的server.xml或context.xml
全域性的資料來源:
如果需要配置全域性的 Resource,則在server.xml的GlobalNamingResources節點裡加入Resource,再在Context節點裡加入ResourceLink的配置。
全域性的resource只是為了重用,方便所有該tomcat下的web工程的資料來源管理,但如果你的tomcat不會同時載入多個web工程,也就是說一個tomcat只載入一個web工程時,是沒有必要配置全域性的resource的。
每個web工程一個資料來源:
在$CATALINA_HOME/conf/context.xml的根節點Context里加入Resource配置。這種配置方法,你在context.xml配置了一個資料來源,但Tomcat中有同時執行著5個工程,那了就壞事兒了,這個在Tomcat啟動時資料來源被建立了5份,每個工程1份資料來源。連線數會是你配置的引數的5倍。
只有在你的Tomcat只載入一個web工程時,才可以直接以context.xml配置資料來源。
<Resource name="jdbc/testDB" //指定的jndi名稱,會用於spring資料來源bean的配置和ResourceLink的配置
type="javax.sql.DataSource" //資料來源床型,使用標準的javax.sql.DataSource
driverClassName="com.mysql.jdbc.Driver" //JDBC驅動器
url="jdbc:mysql://localhost:3306/test" //資料庫URL地址
username="test" //資料庫使用者名稱
password="test" //資料庫密碼
maxIdle="40" //最大的空閒連線數
maxWait="4000" //當池的資料庫連線已經被佔用的時候,最大等待時間
maxActive="40" //連線池當中最大的資料庫連線
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true" //被丟棄的資料庫連線是否做記錄,以便跟蹤
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" />
這裡的factory指的是該Resource 配置使用的是哪個資料來源配置類,這裡使用的是tomcat自帶的標準資料來源Resource配置類,這個類也可以自己寫,實現javax.naming.spi.ObjectFactory 介面即可。某些地方使用的commons-dbcp.jar中的org.apache.commons.dbcp.BasicDataSourceFactory,如果使用這個就需把commons-dbcp.jar及其依賴的jar包,都放在tomcat的lib下,光放在工程的WEB-INF/lib下是不夠的。
ResourceLink 的配置有多種:
1)tomcat安裝目錄下的conf/context.xml,把全域性的resource直接公開給該tomcat下的所有web工程,在Context節點中加入:
<ResourceLink global="jdbc/testMDB" name="jdbc/testMDB" type="javax.sql.DataSource"/>
不建議在此檔案中,不使用<ResourceLink/>,而使用<Resource/>直接配置資料來源,原因上面已說明了。
2)tomcat安裝目錄下的conf/server.xml,該方法可以指定把哪些source繫結到哪個web工程下。
<!-- 新增,第一行為載入的工程配置,第二行是該工程需要的ResourceLink配置 -->
<context docBase="/web/webapps/phoenix" path="" reloadable="false">
<ResourceLink global="jdbc/testMDB" name="jdbc/testMDB" type="javax.sql.DataSource"/>
</context>
也可在此檔案中,不使用<ResourceLink/>,而使用<Resource/>直接配置資料來源。
3)安裝目錄下的conf/localhost/下建立一個xml檔案,檔名是<yourAppName>.xml。比如工程名為test,則該xml名為test.xml。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<ResourceLink global="jdbc/testMDB" name="jdbc/testMDB" type="javax.sql.DataSource"/>
</context>
也可在此檔案中,不使用<ResourceLink/>,而使用<Resource/>直接配置資料來源。
4)tomcat安裝目錄下的\webapps\test\META-INF\context.xml的Context節點中增加:
<ResourceLink global="jdbc/testMDB" name="jdbc/testMDB" type="javax.sql.DataSource"/>
也可在此檔案中,不使用<ResourceLink/>,而使用<Resource/>直接配置資料來源。
本文內容都在tomcat6.0上執行測試過,還下載了commons DBCP的原始碼,加入了跟蹤日誌,用於驗證本文的理論。
連線池排名(純個人看法)
-----------------------------
Tomcat JDBC pool
DBCP 1.4
c3p0 速度不錯
BoneCP 速度不錯,但會啟用很多附加執行緒做回收、關閉工作。
Proxool 在高併發時出現異常
DBCP 1.2
DBPool 最差,墊底。
參考文件《Java連線池評估報告》
http://elf8848.iteye.com/blog/1931778
相關文章
- 從原始碼分析DBCP資料庫連線池的原理原始碼資料庫
- DBCP連線池配置引數說明
- java資料庫連線池dbcp的使用Java資料庫
- DBCP 資料連線池的配置和使用
- 基於HiKariCP元件,分析連線池原理元件
- tomcat自帶連線池dbcp配置以及最佳化說明Tomcat
- 求教怎樣使用commons-dbcp元件的連線池問題元件
- swoole連線池原理解釋
- 資料庫連線池原理資料庫
- 資料庫連線池優化配置(druid,dbcp,c3p0)資料庫優化UI
- Tomcat DBCP(Database Connection Pool) 資料庫連線池入門介紹TomcatDatabase資料庫
- 資料庫連線池的工作原理資料庫
- 25、連線池(DBCP、C3P0)、動態代理與分頁技術
- 常用資料庫連線池 (DBCP、c3p0、Druid) 配置說明資料庫UI
- ServiceStack.Redis的原始碼分析(連線與連線池)Redis原始碼
- 連線池
- OkHttp 3.7原始碼分析(五)——連線池HTTP原始碼
- 解密httpclient,dbcp,jedis,c3p0,druid,okhttp都在使用的連線池技術解密HTTPclientUI
- 資料庫連線池的實現及原理資料庫
- 資料庫連線池原理及作用淺談資料庫
- 菜鳥問題:資料庫連線池原理?資料庫
- Go連線池Go
- HTTP連線池HTTP
- django連線池Django
- Http持久連線與HttpClient連線池HTTPclient
- 連線池和連線數詳解
- OkHttp3原始碼分析[複用連線池]HTTP原始碼
- ElasticSearch連線池建立Elasticsearch
- 自定義連線池
- golang tcp連線池GolangTCP
- Oracle 連線池配置Oracle
- oracle occi 連線池Oracle
- Resin 配置連線池
- [尋]連線池例子
- proxool連線池 配置
- 連線池 druidUI
- java連線池解決連線中斷Java
- proxool連線池如何使用SSL方式連線?