HTTP 無狀態特性導致每次請求都建立新資料庫連線,造成:
Tomcat 內建 DBCP (Database Connection Pool),透過 JNDI 統一管理 DataSource,實現連線重用、預先建立、驗證與自動回收。
https://tomcat.apache.org/download-60.cgi必須使用 Microsoft 官方舊版驅動,新版驅動不支援 SQL 2000:
https://www.microsoft.com/downloads/details.aspx?FamilyID=99b21b65-6d79-4a58-87f5-5a5e4d5b5b5b (搜尋 "SQL Server 2000 JDBC Driver")msbase.jar、mssqlserver.jar、msutil.jar$CATALINA_HOME/lib/ 目錄 (Tomcat 6/7/8/9 通用)編輯 $CATALINA_HOME/conf/context.xml,在 <Context> 內新增:
<Resource name="jdbc/DBTest"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="sa"
password="your_password"
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
url="jdbc:microsoft:sqlserver://192.168.1.100:1433;DatabaseName=Plat_01358"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="60000"
minEvictableIdleTimeMillis="300000" />
| 屬性 | 建議值 | 說明 |
|---|---|---|
| name | jdbc/您的名稱 | JNDI 查找鍵,程式碼中對應 |
| maxActive | 100 | 最大活躍連線數,視 DB 最大連線數調整 |
| maxIdle | 30 | 閒置保留連線數,減少建立開銷 |
| maxWait | 10000 | 取得連線最長等待毫秒數,防止無限阻塞 |
| validationQuery | SELECT 1 | 連線有效性檢查 SQL,SQL Server 專用 |
| testOnBorrow | true | 借用時驗證,確保連線存活 |
| testWhileIdle | true | 空閒檢測器定期驗證 |
import javax.naming.*;
import javax.sql.DataSource;
import java.sql.*;
public class UserDao {
public void queryUser(String userNum) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 1. 取得 JNDI 初始上下文
Context initCtx = new InitialContext();
// 2. 查找 DataSource (java:/comp/env/ + resource name)
DataSource ds = (DataSource) initCtx.lookup("java:/comp/env/jdbc/DBTest");
// 3. 從連線池取得連線
conn = ds.getConnection();
// 4. 使用 PreparedStatement 防注入
String sql = "SELECT PS_NUM, PS_NAME FROM Person WHERE PS_NUM = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userNum);
// 5. 執行查詢
rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("PS_NUM") + " " + rs.getString("PS_NAME"));
}
} catch (NamingException | SQLException e) {
e.printStackTrace();
throw new RuntimeException("資料庫操作失敗", e);
} finally {
// 6. 逆序關閉資源 (連線歸還池中,非實際關閉)
closeQuietly(rs);
closeQuietly(pstmt);
closeQuietly(conn);
}
}
private void closeQuietly(AutoCloseable resource) {
if (resource != null) try { resource.close(); } catch (Exception ignore) {}
}
}
<%@ page import="javax.naming.*,javax.sql.*,java.sql.*" %>
<%
String userNum = request.getParameter("num");
if (userNum == null || userNum.trim().isEmpty()) {
out.println("請提供 num 參數");
return;
}
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Context envCtx = new InitialContext();
DataSource ds = (DataSource) envCtx.lookup("java:/comp/env/jdbc/DBTest");
conn = ds.getConnection();
pstmt = conn.prepareStatement("SELECT PS_NUM, PS_NAME FROM Person WHERE PS_NUM = ?");
pstmt.setString(1, userNum);
rs = pstmt.executeQuery();
if (!rs.isBeforeFirst()) {
out.println("查無資料");
} else {
while (rs.next()) {
out.println("編號: " + rs.getString("PS_NUM") + ", 姓名: " + rs.getString("PS_NAME") + "<br>");
}
}
} catch (Exception e) {
out.println("系統錯誤:" + e.getMessage());
e.printStackTrace(); // 實際專案請用 Logger
} finally {
if (rs != null) try { rs.close(); } catch (Exception ignore) {}
if (pstmt != null) try { pstmt.close(); } catch (Exception ignore) {}
if (conn != null) try { conn.close(); } catch (Exception ignore) {}
}
%>
| 現象 | 可能原因 | 解決方案 |
|---|---|---|
| NameNotFoundException: jdbc/DBTest | JNDI 名稱錯誤 | 確認 context.xml name 屬性與 lookup 字串一致 (含 java:/comp/env/ 前綴) |
| ClassNotFoundException: SQLServerDriver | JAR 未放入 lib | 三個 JAR 必須在 $CATALINA_HOME/lib,重啟 Tomcat |
| Connection refused / Network error | IP/埠/防火牆 | telnet IP 1433 測試連通性;SQL Server 設定允許 TCP/IP |
| 中文亂碼 | 編碼不一致 | JSP pageEncoding=UTF-8、DB 欄位用 NVARCHAR、JDBC URL 加 ;useUnicode=true;characterEncoding=UTF-8 |
| 連線洩漏 (池耗盡) | 未在 finally 關閉 | 強制使用 try-with-resources 或 closeQuietly 模式 |
| Stale connection (通訊鏈路斷裂) | DB 端斷開閒置連線 | 啟用 validationQuery + testOnBorrow + testWhileIdle |
NumActive、NumIdle、MaxWaitTimeremoveAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" 偵測未歸還連線完成上述配置,即可在 Tomcat 應用中獲得高可用、高效能的 SQL Server 2000 資料庫連線管理能力。