JDBC 直接創建連接 (DriverManager.getConnection()) 存在嚴重性能問題:
連接池通過預創建、復用、生命周期管理解決上述問題。本文基於成熟的 Apache Commons DBCP 1.4 (Tomcat 內置版) 實現生產級連接池管理器。
package com.cdv.mam.db;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DBManager {
private static final Log log = LogFactory.getLog(DBManager.class);
private static final String CONFIG_FILE = "dbcp.properties";
private static DataSource dataSource;
// 靜態初始化塊:應用啟動時構建連接池
static {
Properties dbProperties = new Properties();
try {
// 從 classpath 載入配置
dbProperties.load(DBManager.class.getClassLoader()
.getResourceAsStream(CONFIG_FILE));
// 工廠模式創建 DataSource
dataSource = BasicDataSourceFactory.createDataSource(dbProperties);
// 啟動驗證:獲取連接、打印數據庫信息、釋放連接
Connection conn = getConn();
DatabaseMetaData mdm = conn.getMetaData();
log.info("Connected to " + mdm.getDatabaseProductName() + " "
+ mdm.getDatabaseProductVersion());
if (conn != null) conn.close();
} catch (Exception e) {
log.error("初始化連接池失敗:" + e);
throw new ExceptionInInitializerError(e); // 失敗快速失敗
}
}
private DBManager() {} // 防止實例化
/**
* 獲取連接 (從池中借用)
* @return Connection 或 null (記錄錯誤日誌)
*/
public static final Connection getConn() {
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
log.error("獲取數據庫連接失敗:" + e);
}
return conn;
}
/**
* 歸還連接 (關閉邏輯實為歸還池中)
* @param conn 需歸還的連接
*/
public static void closeConn(Connection conn) {
try {
if (conn != null && !conn.isClosed()) {
conn.setAutoCommit(true); // 重置自動提交,防止事務殘留
conn.close(); // 實際調用 DataSource 的 close() → 歸還池中
}
} catch (SQLException e) {
log.error("關閉數據庫連接失敗:" + e);
}
}
}
# === 基礎連接配置 ===
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.1.41:3306/dmc?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username=root
password=root
# === 連接池核心參數 ===
# 最大活躍連接數:0=無限制,生產建議 20-100 (視數據庫 max_connections)
maxActive=30
# 最大空閒連接數:池中保持的空閒連接上限,0=無限制
maxIdle=10
# 最大等待時間(毫秒):池耗盡時獲取連接的最大阻塞時間,-1=無限等待
maxWait=1000
# === 連接驗證與清理 ===
# 檢測廢棄連接:超過 removeAbandonedTimeout 仍未歸還視為泄漏
removeAbandoned=true
removeAbandonedTimeout=180 # 秒,建議 > 最長業務事務耗時
# 空閒連接驗證:定期檢查空閒連接有效性
validationQuery=SELECT 1
testWhileIdle=true
timeBetweenEvictionRunsMillis=30000 # 30秒檢查一次
minEvictableIdleTimeMillis=300000 # 空閒 5分鐘後可被驅逐
# === 預備語句池 (可選,提升性能) ===
poolPreparedStatements=true
maxOpenPreparedStatements=20
| 參數 | 推薦值 | 調優原則 |
|---|---|---|
| maxActive | CPU核心數 × 2 ~ 4 | 數據庫 max_connections 總量 / 應用實例數 - 預留量 |
| maxIdle | ≈ maxActive × 0.3-0.5 | 平衡響應速度與資源佔用 |
| maxWait | 1000-5000ms | 避免無限阻塞導致線程堆積,配合熔斷機制 |
| removeAbandonedTimeout | 最長事務時間 × 2 | 防誤殺正常長事務,需配合監控告警 |
| validationQuery | SELECT 1 / SELECT 1 FROM DUAL | 極輕量、無副作用、權限最小 |

commons-dbcp-1.4.jar:連接池核心實現commons-pool-1.5.4.jar:對象池基礎框架 (DBCP 依賴)commons-logging-1.1.1.jar:日誌門面mysql-connector-java-5.1.x.jar:MySQL JDBC 驅動注意:Tomcat 內置 tomcat-dbcp.jar (重新打包的 DBCP),若在 Tomcat 中運行可直接使用 org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory 避免 JAR 衝突。
public class UserDao {
public User findById(String id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBManager.getConn();
ps = conn.prepareStatement("SELECT * FROM t_user WHERE id = ?");
ps.setString(1, id);
rs = ps.executeQuery();
if (rs.next()) {
return mapRow(rs);
}
return null;
} catch (SQLException e) {
throw new DaoException("查詢用戶失敗", e);
} finally {
// 必須按逆序關閉,確保連接歸還池中
closeQuietly(rs);
closeQuietly(ps);
DBManager.closeConn(conn);
}
}
private void closeQuietly(AutoCloseable closeable) {
if (closeable != null) try { closeable.close(); } catch (Exception ignored) {}
}
}
DBCP 1.x 已停止維護,DBCP 2.x 性能一般。現代項目強烈推薦 HikariCP (Spring Boot 2.x 默認):
# HikariCP 配置示例 (application.yml)
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/dmc?useSSL=false&serverTimezone=UTC
username: root
password: root
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 300000
max-lifetime: 1200000
connection-timeout: 30000
connection-test-query: SELECT 1
pool-name: MyAppHikariCP
HikariCP 優勢:零開銷架構、字節碼級優化、更智能的驅逐策略、完整的 JMX 指標、更小的 JAR 體積 (約 150KB)。
連接池是數據庫訪問層的基石。正確配置 maxActive、maxIdle、maxWait、validationQuery 等核心參數,啟用 removeAbandoned 防洩漏,配合 testWhileIdle 保活,可構建高可用、高性能的數據庫訪問基礎設施。現代項目建議直接使用 HikariCP,但理解 DBCP 原理對維護老系統、排查連接洩漏問題仍有重要價值。