Tomcat 的 JDBC 連線池

FrankYou發表於2018-03-16

JDBC 連線池 org.apache.tomcat.jdbc.pool 是 Apache Commons DBCP 連線池的一種替換或備選方案。

那究竟為何需要一個新的連線池?

原因如下:

Commons DBCP 1.x 是單執行緒。為了執行緒安全,在物件分配或物件返回的短期內,Commons 鎖定了全部池。但注意這並不適用於 Commons DBCP 2.x。
Commons DBCP 1.x 可能會變得很慢。當邏輯 CPU 數目增長,或者試圖借出或歸還物件的併發執行緒增加時,效能就會受到影響。高併發系統受到的影響會更為顯著。注意這並不適用於 Commons DBCP 2.x。
Commons DBCP 擁有 60 多個類。tomcat-jdbc-pool 核心只有 8 個類。因此為了未來需求變更著想,肯定需要更少的改動。我們真正需要的只是連線池本身,其餘的只是附屬。
Commons DBCP 使用靜態介面,因此對於指定版本的 JRE,只能採用正確版本的 DBCP,否則就會出現 NoSuchMethodException 異常。
當DBCP 可以用其他更簡便的實現來替代時,實在不值得重寫那 60 個類。


Tomcat JDBC 連線池無需為庫本身新增額外執行緒,就能獲取非同步獲取連線。
Tomcat JDBC 連線池是 Tomcat 的一個模組,依靠 Tomcat JULI 這個簡化了的日誌架構。
使用 javax.sql.PooledConnection 介面獲取底層連線。
防止飢餓。如果池變空,執行緒將等待一個連線。當連線返回時,池就將喚醒正確的等待執行緒。大多數連線池只會一直維持飢餓狀態。

Tomcat JDBC 連線池還具有一些其他連線池實現所沒有的特點:

支援高併發環境與多核/CPU 系統。

介面的動態實現。支援 java.sql 與 java.sql 介面(只要 JDBC 驅動),甚至在利用低版本的 JDK 來編譯時。

驗證間隔時間。我們不必每次使用單個連線時都進行驗證,可以在借出或歸還連線時進行驗證,只要不低於我們所設定的間隔時間就行。

只執行一次查詢。當與資料庫建立起連線時,只執行一次的可配置查詢。這項功能對會話設定非常有用,因為你可能會想在連線建立的整個時段內都保持會話。

能夠配置自定義攔截器。通過自定義攔截器來增強功能。可以使用攔截器來採集查詢統計,快取會話狀態,重新連線之前失敗的連線,重新查詢,快取查詢結果,等等。由於可以使用大量的選項,所以這種自定義攔截器也是沒有限制的,跟 java.sql/javax.sql 介面的 JDK 版本沒有任何關係。

高效能。後文將舉例展示一些效能差異。

極其簡單。它的實現非常簡單,程式碼行數與原始檔都非常少,這都有賴於從一開始研發它時,就把簡潔當做重中之重。對比一下 c3p0 ,它的原始檔超過了 200 個(最近一次統計),而 Tomcat JDBC 核心只有 8 個檔案,連線池本身則大約只有這個數目的一半,所以能夠輕易地跟蹤和修改可能出現的 Bug。

非同步連線獲取。可將連線請求佇列化,系統返回 Future<Connection>。

更好地處理空閒連線。不再簡單粗暴地直接把空閒連線關閉,而是仍然把連線保留在池中,通過更為巧妙的演算法控制空閒連線池的規模。

可以控制連線應被廢棄的時間。當池滿了即廢棄,或者指定一個池使用容差值,發生超時就進行廢棄處理。通過查詢或語句來重置廢棄連線計時器。允許一個使用了很長時間的連線不因為超時而被廢棄。這一點是通過使用 ResetAbandonedTimer 來實現的。經過指定時間後,關閉連線。與返回池的時間相類似。當連線要被釋放時,獲取 JMX 通知並記錄所有日誌。它類似於 removeAbandonedTimeout,但卻不需要採取任何行為,只需要報告資訊即可。通過 suspectTimeout 屬性來實現。可以通過 java.sql.Driver、javax.sql.DataSource 或 javax.sql.XADataSource 獲取連線。通過 dataSource 與 dataSourceJNDI 屬性實現這一點。支援 XA 連線。

相關文章