Java Web 應用在 Tomcat 中使用資料庫連線池,標準做法是配置 JNDI DataSource,由容器管理連線生命週期,應用通過 JNDI 查找獲取連線。本文針對 Tomcat 8.5/9.0/10.1,詳解兩種主流配置方式、常見報錯排查與效能調優參數。
<!-- $CATALINA_HOME/conf/server.xml,在 <GlobalNamingResources> 區塊內 -->
<Resource
name="jdbc/myapp"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=Asia/Taipei&allowPublicKeyRetrieval=true"
username="app_user"
password="StrongPassword!"
maxTotal="50"
maxIdle="20"
minIdle="5"
maxWaitMillis="10000"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="30000"
minEvictableIdleTimeMillis="60000"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="60"
logAbandoned="true"
/>
然後在同檔案的 `
<ResourceLink
name="jdbc/myapp"
global="jdbc/myapp"
type="javax.sql.DataSource"
/>
選項 A:Tomcat 全域 context.xml(`$CATALINA_HOME/conf/context.xml`)
<Context>
<Resource
name="jdbc/myapp"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=Asia/Taipei"
username="app_user"
password="StrongPassword!"
maxTotal="50"
maxIdle="20"
minIdle="5"
maxWaitMillis="10000"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
/>
</Context>
選項 B:WebApp 專屬 META-INF/context.xml(`src/main/webapp/META-INF/context.xml`,隨 WAR 部署,最推薦)
<Context antiResourceLocking="true">
<Resource
name="jdbc/myapp"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=Asia/Taipei"
username="app_user"
password="StrongPassword!"
maxTotal="30"
maxIdle="15"
minIdle="3"
maxWaitMillis="5000"
validationQuery="SELECT 1"
testOnBorrow="true"
/>
</Context>
# application.yml (Spring Boot 2.x/3.x)
spring:
datasource:
jndi-name: java:comp/env/jdbc/myapp
# 若不想用 JNDI,直接配置 HikariCP 參數即可,無需 Tomcat DataSource
# hikari:
# maximum-pool-size: 30
# minimum-idle: 5
# ...
# 使用方式同普通 DataSource
@Autowired
private DataSource dataSource;
// 或注入 JdbcTemplate / EntityManager / SqlSessionFactory
| 錯誤訊息 | 原因 | 解決 |
|---|---|---|
| Cannot create JDBC driver of class '' for connect URL 'null' | Resource 定義未生效、名稱不匹配、context.xml 未被讀取 | 檢查 Resource name 與 lookup 名稱一致;確認 context.xml 位置正確;Tomcat 重啟後查看管理介面 Resources 頁面 |
| Name [jdbc/myapp] is not bound in this Context | JNDI 名稱錯誤、未宣告 resource-ref | web.xml 宣告 ` |
| Communications link failure | 網路不通、MySQL bind-address、防火牆、SSL 協商失敗 | 測試 `telnet host 3306`;MySQL `bind-address=0.0.0.0`;URL 加 `useSSL=false` 或配置信任憑證 |
| Public Key Retrieval is not allowed | MySQL 8.0 caching_sha2_password 需公開金鑰 | URL 加 `allowPublicKeyRetrieval=true` 或改用 `mysql_native_password` |
| Connection has been abandoned | 連線洩漏(未 close、事務未提交/回滾) | 啟用 `removeAbandonedOnBorrow=true`;代碼確保 try-with-resources 關閉連線;排查長事務 |
| Pool exhausted / maxWaitMillis timeout | 連線池耗盡、洩漏、或 maxTotal 太小 | 監控 `numActive`/`numIdle`;調大 maxTotal;修復洩漏;優化慢查詢釋放連線 |
連線池是 Java Web 與資料庫的「生命線」。配置規範、參數合理、監控到位,才能在高併發下穩如磐石。