資料庫連線建立成本高,頻繁開關會嚴重拖慢應用效能。Apache Commons DBCP (Database Connection Pool) 是經典的連線池實作,本文將詳細說明如何在 Java 專案中整合 DBCP 2.x,涵蓋 Maven 依賴、核心配置參數、程式碼範例與效能調優建議。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version> <!-- 請檢查最新版本 -->
</dependency>
<!-- 資料庫驅動,以 MySQL 為例 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
package com.example.config;
import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;
public class DBCPConfig {
private static final BasicDataSource DATA_SOURCE = new BasicDataSource();
static {
// 基本連線資訊
DATA_SOURCE.setDriverClassName("com.mysql.cj.jdbc.Driver");
DATA_SOURCE.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");
DATA_SOURCE.setUsername("root");
DATA_SOURCE.setPassword("password");
// 連線池核心參數
DATA_SOURCE.setInitialSize(5); // 初始連線數
DATA_SOURCE.setMinIdle(5); // 最小閒置連線
DATA_SOURCE.setMaxIdle(10); // 最大閒置連線
DATA_SOURCE.setMaxTotal(20); // 最大連線數(舊版 maxActive)
DATA_SOURCE.setMaxWaitMillis(30000); // 取得連線最大等待時間(ms)
// 連線驗證機制(關鍵:防止資料庫斷開導致的失效連線)
DATA_SOURCE.setValidationQuery("SELECT 1");
DATA_SOURCE.setTestOnBorrow(true); // 借用時驗證
DATA_SOURCE.setTestOnReturn(false); // 歸還時驗證(通常關閉以提升效能)
DATA_SOURCE.setTestWhileIdle(true); // 閒置驗證
DATA_SOURCE.setTimeBetweenEvictionRunsMillis(60000); // 驗證間隔
DATA_SOURCE.setMinEvictableIdleTimeMillis(300000); // 最小閒置存活時間
// 其他優化
DATA_SOURCE.setDefaultAutoCommit(true);
DATA_SOURCE.setAccessToUnderlyingConnectionAllowed(true); // 允許取得原生連線
}
public static DataSource getDataSource() {
return DATA_SOURCE;
}
public static void shutdown() throws SQLException {
DATA_SOURCE.close();
}
}
| 參數 | 預設值 | 建議值 | 說明 |
|---|---|---|---|
| initialSize | 0 | 5~10 | 啟動時建立的連線數,減少首次請求延遲 |
| maxTotal | 8 | 20~50 | 池中最大連線數,視資料庫 max_connections 與應用併發調整 |
| maxIdle | 8 | 10~20 | 池中保留的最大閒置連線,超過者會被逐出 |
| minIdle | 0 | 同 initialSize | 最小閒置連線,低於此值會補充新連線 |
| maxWaitMillis | -1(無限等待) | 10000~30000 | 連線耗盡時等待毫秒數,避免無限阻塞 |
| validationQuery | 無 | SELECT 1 | 驗證連線有效性的 SQL,MySQL 用 SELECT 1,Oracle 用 SELECT 1 FROM DUAL |
| testOnBorrow | false | true | 每次借用前執行 validationQuery,確保連線存活 |
| testWhileIdle | false | true | 由背景執行緒定期檢查閒置連線 |
| timeBetweenEvictionRunsMillis | -1 | 30000~60000 | 閒置連線驗證執行間隔 |
package com.example.dao;
import com.example.config.DBCPConfig;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class UserDao {
private final DataSource dataSource = DBCPConfig.getDataSource();
public List<String> getAllUsernames() {
String sql = "SELECT username FROM users";
List<String> list = new ArrayList<>();
// try-with-resources 自動關閉連線、Statement、ResultSet
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
list.add(rs.getString("username"));
}
} catch (SQLException e) {
throw new RuntimeException("查詢失敗", e);
}
return list;
}
}
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="password" />
<property name="initialSize" value="5" />
<property name="maxTotal" value="20" />
<property name="maxIdle" value="10" />
<property name="minIdle" value="5" />
<property name="maxWaitMillis" value="30000" />
<property name="validationQuery" value="SELECT 1" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
</bean>
Spring Boot 2.x 預設使用 HikariCP,若堅持用 DBCP2:
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.dbcp2.initial-size=5
spring.datasource.dbcp2.max-total=20
spring.datasource.dbcp2.max-idle=10
spring.datasource.dbcp2.min-idle=5
spring.datasource.dbcp2.max-wait-millis=30000
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-while-idle=true
BasicDataSource 實作 ManagedDataSource,可透過 JConsole、VisualVM 觀察 NumActive、NumIdle、NumWaiting 指標。finally 區塊關閉 Connection,歸還池中。maxTotal = (核心數 * 2) + 有效磁碟數,但受限於資料庫 max_connections。testOnBorrow=true、validationQuery 正確,並檢查資料庫 wait_timeout (MySQL 預設 8 小時) 是否小於池的 minEvictableIdleTimeMillis。maxTotal、優化慢查詢縮短佔用時間。com.mysql.cj.jdbc.Driver。正確配置連線池是資料庫應用高效能穩定運行的基石,建議從預設值開始,結合壓力測試與監控指標逐步調優。