如何在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瀏覽器


您可在下列課程中了解更多技巧喔!