Tomcat 內置高性能連接池,通過 JNDI 將 DataSource 綁定到 java:comp/env 命名上下文,應用代碼零依賴具體池實現,僅面向 javax.sql.DataSource 接口編程。本文詳細演示 context.xml、web.xml、Servlet 註入的完整配置鏈路。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
name="jdbc/mySource"
type="javax.sql.DataSource" -- 標準接口類型
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/java?useSSL=false&serverTimezone=UTC"
maxActive="20" -- 最大活躍連接
maxIdle="10" -- 最大閒置連接
minIdle="5" -- 最小閒置連接
maxWait="3000" -- 獲取連接超時(ms)
validationQuery="SELECT 1" -- 連接有效性檢查
testOnBorrow="true" -- 借用時檢查
testWhileIdle="true" -- 閒置時檢查
timeBetweenEvictionRunsMillis="60000"
/>
</Context>
位置:Web 專案 src/main/webapp/META-INF/context.xml(Maven 標準目錄),打包後自動進入 WEB-INF/classes/META-INF/ 或 WAR 根目錄 META-INF/。
<resource-ref>
<res-ref-name>jdbc/mySource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth> -- 容器管理認證
</resource-ref>
聲明後,IDE 可提示,部署描述符完整性更好。
public class DataSourceServlet extends HttpServlet {
private DataSource dataSource;
@Override
public void init() throws ServletException {
try {
// 1. 獲取初始上下文
Context initCtx = new InitialContext();
// 2. 查找 java:comp/env 環境上下文
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// 3. 查找 DataSource (名稱對應 context.xml 的 name 屬性)
dataSource = (DataSource) envCtx.lookup("jdbc/mySource");
} catch (NamingException e) {
throw new ServletException("JNDI 查找 DataSource 失敗", e);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user")) {
while (rs.next()) {
System.out.println(rs.getString("username"));
}
} catch (SQLException e) {
throw new ServletException("數據庫操作異常", e);
}
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| NameNotFoundException | JNDI 名稱不匹配 | 核對 context.xml name、web.xml res-ref-name、代碼 lookup 三者一致 |
| ClassNotFoundException: Driver | 驅動包不在 Tomcat classpath | 將 mysql-connector-java.jar 放入 $CATALINA_HOME/lib |
| 連接泄漏 | 未關閉 Connection/Statement/ResultSet | 務必使用 try-with-resources 或 finally 關閉 |
| 需在 Servlet init 獲取 | JNDI 上下文需 Web 容器初始化完成 | 配置 <load-on-startup>1</load-on-startup> 確保啟動時初始化 |
<servlet>
<servlet-name>DataSourceServlet</servlet-name>
<servlet-class>com.example.DataSourceServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DataSourceServlet</servlet-name>
<url-pattern>/datasource-demo</url-pattern>
</servlet-mapping>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/mySource"
resource-ref="true" proxy-interface="javax.sql.DataSource" />
@Bean
public DataSource dataSource() throws NamingException {
JndiTemplate jndi = new JndiTemplate();
return (DataSource) jndi.lookup("java:comp/env/jdbc/mySource");
}
context.xml 調整池參數,無需重新編譯打包resource-ref 規範,可移植至其他容器掌握 Tomcat JNDI DataSource 配置,是從「寫死連接池代碼」向「企業級部署運維」邁進的關鍵一步。建議在開發環境同步配置,養成「代碼只依賴接口,配置由容器注入」的良好習慣。