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