如何在Tomcat伺服器建置Connection Pool
戴玉佩 Patty Tai
- 精誠資訊/恆逸教育訓練中心-資深講師
- 技術分類:程式設計
軟體應用系統幾乎都要用到資料庫環境。因此不論哪一種程式語言,只要能開發正式的後端系統,都需要提供與資料庫有效連結互動的API(以Java來說就是JDBC、JPA)。開發人員在撰寫資料庫的相關功能時,一開始最重要的就是取得資料庫連線,然後才能準備、執行SQL指令、處理查詢結果…等。完成後,也務必確實關閉連線,讓珍貴的Database連線物件不至被浪費。但是這樣的做法在Web Application的運作架構中,因為會隨著尖峰時段一波一波使用者湧入,大量取得資料庫連線、又在快速完成後斷線,造成資料庫伺服器不停忙於資料庫連線連線、管理、斷線的地獄。
圖1. 因前端請求大量建立資料庫連線
圖2. 請求處理結束前,大量關閉資料庫連線
為了解決這樣的問題,大部分Web伺服器都有提供Connection Pool,也就是「資料庫連線儲存池」的機制。Java Web伺服器當然也有。
圖3. 因前端請求,從儲存池取得資料庫連線
圖4. 請求處理結束前關閉的連線,保留在儲存池中給後續的請求使用
這裡就以Tomcat為例,來示範如何建置Java Web伺服器的Connection Pool:
1.在Web Application執行路徑的[META-INF]資料夾中,建立context.xml檔案:
圖5. Tomcat[連線儲存池設定]之context.xml檔案部署位置
2.編輯context.xml檔案如下:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true">
<Resource
auth="Container"
name="jdbc/abc"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/abc"
username="資料庫連線帳號"
password="資料庫連線密碼"
maxIdle="10"
maxWait="-1"
factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory"
maxActive="20"/>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<CookieProcessor sameSiteCookies="none" />
</Context>
3.在[WEB-INF/lib]資料夾中要部署資料庫所需的JDBC Driver程式庫
圖6. 部署JDBC Driver程式庫
4.原來在DAO類別中負責建立資料庫連線的程式,要改成從[Connection Pool]來取得連線:
package uuu.vgb.service;
import java.sql.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import uuu.vgb.exception.VGBException;
class RDBConnection {
private static final String driver = "com.mysql.cj.jdbc.Driver";
private static final String url="jdbc:mysql://localhost:3306/abc";
private static final String userId = "資料庫連線帳號";
private static final String pwd = "資料庫連線密碼";
static Connection getConnection() throws VGBException {
Connection connection = null;
try {
DataSource ds = null;
Context ctx = new InitialContext();
if (ctx == null)
throw new VGBException("無法取得伺服器環境JNDI.");
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/abc");
if (ds == null)
throw new VGBException("無法取得伺服器的連線儲存池資源.");
connection = ds.getConnection();
System.out.println("從連線儲存池取得:"+connection); //for test
return connection;
} catch (Exception ex) {
try {
Class.forName(driver);//1.載入JDBC Driver
try {
connection =
DriverManager.getConnection(url, userId, pwd);//2.建立連線
System.out.println("取得一班連線物件:"
+connection.getClass().getName()); //for test
return connection;
} catch (SQLException e) {
throw new VGBException("建立連線失敗",e);
}
} catch (ClassNotFoundException e) {
throw new VGBException("載入JDBC Driver失敗:" + driver);
}
}
}
}
*注意:JDBC資源名稱必須相同:
圖7.程式與設定檔context.xml注意事項
完成後即可啟動Web Application來測試看看。 從瀏覽器送出資料庫查詢的請求後,從伺服器的[主控台畫面]檢視測試用訊息,即可看到已經從[連線儲存池]取得的連線了:
圖8.Web伺服器的主控台vs瀏覽器