C3P0鏈接池解析

C3P0鏈接池解析java

1,鏈接池的原理和意義
無論什麼樣的鏈接池其核心意義都是一致的,就是爲一個項目建立鏈接對象,保存在池中待用。每次訪問時從池中
獲取已經存在的鏈接,使用完畢後,再返回池中。從而減小了建立鏈接和銷燬鏈接而浪費的系統資源。本文會分析
目前經常使用鏈接池之一C3P0。
2,C3P0簡單配置
c3p0鏈接池做爲咱們開發中最爲經常使用的鏈接池之一使用起來是很是簡單的。本文將從原理角度來分析一下 C3P0連
接池的主要架構。
通常只須要配置如下參數便可:
一般狀況下,咱們還會跟本地配置文件properties或者本地xml文件相結合的方式進行操做,以加強代碼的靈活
性。
3,核心類
C3P0鏈接池主要核心類有如下幾個:
ComboPooledDataSource:主要負責鏈接池的配置和獲取池中的鏈接
C3P0PooledConnectionPoolManager:大內總管的角色。
負責生命週期以及生命週期所須要的一些參數。
好比:AdminTaskTimer定時檢測和全局的線程池C3P0PoolConnectionPool:
表示物理鏈接池,自己的業務邏輯相對於比較簡單,主要核心是經過代理ResourcePool來實現邏輯的。
BasicResourcePool:
是BasicResourcePool這個接口的實現類,是大內總管 C3P0PooledConnectionPoolManager的手下。
大內總管管池子,而BasicResourcePool是管池中鏈接的生命週期。
至關於大內中長春宮,寧壽宮等每個宮的管事。
String driverClass = "com.mysql.jdbc.Driver";
String jdbcURL = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "";
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(driverClass);
cpds.setJdbcUrl(jdbcURL);
cpds.setUser(user);
cpds.setPassword(password);
須要用的時候再得到其中的鏈接便可。
Connection conn = cpds.getConnection();
BasicResourcePool.Manager:
是BasicResourcePool的一個助手,協助一塊兒管理鏈接池中的鏈接。
在BasicResourcePool中有幾個任務須要注意:
1,建立鏈接ScatteredAcquireTask
2,銷燬鏈接RemoveTask
3,檢測鏈接是否過時CullTask
4,檢測鏈接是否空閒CheckIdleResourcesTask
4,初始化特色
C3P0鏈接池在初始化的時候並非在建立的時候直接建立並進行初始化的,鏈接池採起了一種「懶初始化」的思
想。那麼何爲懶初始化呢?
本身自己不會不會主動初始化,而是會等到第一個鏈接請求進來以後它纔會初始化。而那個觸發點就是:
當代碼執行到這裏,即獲取到一個鏈接時,纔會進行初始化保證了資源的有效利用。
5,建立鏈接從而下降系統資源消耗
衆所周知,使用鏈接池中的鏈接是爲了下降系統資源消耗,那麼到底是爲何呢?
首先數據庫實際上是一個管理系統,以MySQL爲例,MySQL是一個數據庫管理系統,區分服務端和客戶端,MySQL
指的是這個總體管理系統,因此想要實際的把數據存入到表中,須要經歷如下過程。
創建TCP鏈接,而後經過三次握手協議發送與相應;其次客戶端須要進行帳戶驗證,服務器返回確認;用戶驗證
後,須要傳輸相關鏈接變量如是否自動提交事務的設置等。
因此總而言之,操做數據以前,必定會有屢次數據的交互,而後才能執行真正的執行CURD的sql語句。
鏈接池真正的下降的是以上的這些步驟,當須要對數據庫進行操做時,直接獲取已經存在的,就減小了資源的消
耗。
預先創建多個數據庫鏈接對象,存入到池中。當有客戶端進行請求的時候,取出一個鏈接爲當前客戶端的請求而操
做數據庫,當該客戶端請求操做完畢時,將請求放回鏈接池裏。一直沒有關閉。
6,鏈接池下降消耗的原理圖解
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.getConnection();
北京市昌平區建材城西路金燕龍辦公樓一層 電話:400-618-9090
若是沒有鏈接池,那麼訪問者跟數據庫之間每次都建立一個鏈接,用完再銷燬。
若是用了鏈接池,就不會本身建立,而是從池子中拿,用完再進行歸還。
7,入口類ComboPooledDataSource
在進行初始化建立的時候,會有池子的入口類,就是ComboPooledDataSource。其中gettConnection方法是在
AbstractPoolBackedDataSource類中實現。
其中PooledConnection是javax.sql下的一個接口。針對於這個鏈接的執行者對象,結果集對象和鏈接對象對被
pooledconnection管理。而c3p0實現是NewPooledConnection。
8,BasicResourcePool類
8.1,主要核心代碼:
其中timeout表示鏈接溢出時間。
查看池中是否有未使用的connection,若是有就返回,除此以外,還須要判斷鏈接是否空閒經過timeout判斷鏈接
是否過時,若是沒有最大數,就生成一個,或者就等待。
8.2,主要核心代碼:
AbstractPoolBackedDataSource類的getConnection方法以下:
public Connection getConnection() throwsSQLException{
PooledConnection pc = getPoolManager().getPool().checkoutPooledConnection();
returnpc.getConnection();
} O
bject resc = prelimCheckoutResource(timeout);
booleanrefurb = attemptRefurbishResourceOnCheckout(resc);
獲得鏈接後,檢測鏈接的可用性。 若是鏈接可用,接着判斷鏈接是否處於管理中,若是不在就再調用本方法獲取一
個,若是在,就返回本鏈接。
8.3,添加鏈接
獲取鏈接時由BasicResourcePool類中的prelimCheckoutResource方法觸發,調用過程以下:
1,BasicResourcePool類prelimCheckoutResource方法當可用鏈接數爲0時調用recheckResizePool方法。
2,echeckResizePool方法判斷須要擴容則調用expandPool方法。expandPool方法使用線程池調用AcquireTask
進行擴容。
3,AcquireTask調用mgr.acquireResource方法獲取鏈接,若是鏈接池裏的鏈接未到最大數量將獲取的鏈接加入管
理和未使用的list中,不然銷燬鏈接。
8.4,回收鏈接
由close方法觸發。調用過程以下:
1,C3P0PooledConnectionPool類,的ConnectionEventListenerImpl監聽器類的connectionClosed方法被觸發。
2,判斷同步仍是異步的(默認是同步)。若是是異步,那麼就採用線程池來進行處理回收,若是是同步,那麼就
進行直接調用BasicResourcePool類的checkinResource方法對鏈接進行回收,此處的回收並非銷燬,而是歸
還。
9,死鎖機制
在C3P0中有不少任務都是採起多線程進行處理的。好比添加連接或者是回收鏈接。一旦有這種相似於生產者消費
者的多線程任務,那麼就必需要進行死鎖判斷,不然會進入無線等待狀態。
該機制的是由ThreadPoolAsynchronousRunner類的子類DeadlockDetector來執行具體的操做的。、
DeadlockDetector類繼承了TimerTask類,由其中的Timer來調用DeadlockDetecto運行。DeadlockDetector類中
有兩個屬性:LinkedListlast 和 LinkedListcurrent。
這兩個LinkedList集合放的是等待執行的任務。根據他的屬性名字就很輕易理解,last是上次檢測時待執行的任務
而current是本次檢測時要執行的任務,當pendingTasks不爲空且current.equals( last)時認爲死鎖發生。當一旦確
認死鎖發生了,那麼會把當前任務交給ThreadPerTaskAsynchronousRunner類來處理,這個類會啓用新的線程
DispatchThread來處理當前的任務隊列。
總結:
鏈接池能夠在訪問數據庫時下降系統消耗。因此不論是什麼項目都一定會有鏈接池的存在。
鏈接池基本使用很是的簡單,經過一些簡單的配置便可,可是想要真正把鏈接池原理理解,建議等用熟以後,閒暇
之餘再進行研究。mysql

相關文章
相關標籤/搜索