C3P0 是一個開源的 JDBC 連接池庫,它實現了資料源與 JNDI 綁定,支援 JDBC 3 規格及 JDBC 2 標準擴展。廣泛應用於 Hibernate、Spring 等主流開源框架中。簡單來說,連接池就像一個「連接水池」,預先建立好多個資料庫連接並存放其中,應用程式需要時直接取用,用完歸還,避免頻繁創建銷毀連接的性能開銷。
開始前,請確保專案已引入以下核心 JAR 包(版本號可根據實際情況調整):
c3p0-0.9.5.5.jar(核心包)mchange-commons-java-0.2.19.jar(C3P0 依賴)mysql-connector-java-8.0.xx.jar(MySQL 驅動,建議使用較新版本)junit-4.13.x.jar(單元測試)提示:原文提到的 commons-io-2.0.1.jar 並非 C3P0 必須,視專案需求決定是否引入。
在 MySQL 中建立測試資料庫 test 及 user 表:
CREATE DATABASE IF NOT EXISTS `test` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE `test`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(20) DEFAULT NULL,
`passWord` VARCHAR(100) DEFAULT NULL,
`address` VARCHAR(100) DEFAULT NULL,
`phone_number` VARCHAR(20) DEFAULT NULL,
`create_time` DATETIME DEFAULT NULL,
`update_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` (`id`,`user_name`,`passWord`,`address`,`phone_number`,`create_time`,`update_time`) VALUES
(1,'test','CY9rzUYh03PK3k6DJIE09g==','test','test','2014-03-29 00:48:14','2014-03-29 00:48:17'),
(2,'te2','CY9rzUYh03PK3k6DJIE09g==','asdfk','4156434885','2015-08-05 11:09:29','2015-08-20 11:09:33');
在 src/main/resources 下建立 db.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
核心示例代碼:
package com.example.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class C3p0Demo1 {
@Test
public void getConnection() throws IOException, PropertyVetoException, SQLException {
// 1. 載入配置文件
Properties prop = new Properties();
try (InputStream in = C3p0Demo1.class.getClassLoader().getResourceAsStream("db.properties")) {
prop.load(in);
}
// 2. 建立並配置連接池
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(prop.getProperty("jdbc.driver"));
cpds.setJdbcUrl(prop.getProperty("jdbc.url"));
cpds.setUser(prop.getProperty("jdbc.username"));
cpds.setPassword(prop.getProperty("jdbc.password"));
// 3. 獲取連接並執行查詢
try (Connection conn = cpds.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user");
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id"));
System.out.println("用戶名: " + rs.getString("user_name"));
System.out.println("密碼: " + rs.getString("passWord"));
System.out.println("地址: " + rs.getString("address"));
System.out.println("電話: " + rs.getString("phone_number"));
System.out.println("創建時間: " + rs.getTimestamp("create_time"));
System.out.println("更新時間: " + rs.getTimestamp("update_time"));
System.out.println("-------------------------");
}
}
// try-with-resources 自動關閉連接(歸還池中)、Statement、ResultSet
// cpds.close() 應在應用關閉時調用,此處為演示省略
}
}
關鍵點:conn.close() 並非真正關閉物理連接,而是將連接歸還給連接池。
在 src/main/resources 下建立 固定名稱 c3p0.properties,C3P0 會自動識別:
c3p0.driverClass=com.mysql.cj.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
c3p0.user=root
c3p0.password=root
# 連接池常用調優參數(可選)
c3p0.initialPoolSize=5
c3p0.minPoolSize=5
c3p0.maxPoolSize=20
c3p0.maxIdleTime=1800
c3p0.acquireIncrement=5
代碼極度簡化:
package com.example.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import javax.sql.DataSource;
import java.sql.*;
public class C3p0Demo2 {
@Test
public void getConByC3P0() throws SQLException {
// 無需手動讀取配置,C3P0 自動載入 c3p0.properties
DataSource ds = new ComboPooledDataSource();
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user");
ResultSet rs = ps.executeQuery()) {
System.out.println("獲取到連接: " + conn);
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", 用戶名: " + rs.getString("user_name"));
}
}
}
}
| 參數 | 說明 | 建議值 |
|---|---|---|
| initialPoolSize | 初始化連接數 | 5-10 |
| minPoolSize | 最小保持連接數 | 5-10 |
| maxPoolSize | 最大連接數 | 20-50(視資料庫 max_connections) |
| maxIdleTime | 連接最大空閒時間(秒),超過則被釋放 | 1800 (30分) |
| acquireIncrement | 連接不足時一次創建數量 | 3-5 |
| checkoutTimeout | 等待連接超時時間(毫秒) | 5000 |
| testConnectionOnCheckout | 取出連接時驗證有效性 | true |
Connection、Statement、ResultSet,避免洩漏。ComboPooledDataSource 應作為 Bean 由 Spring 管理,而非方法內 new。numBusyConnections、numIdleConnections、numUnclosedOrphanedConnections 等運行時指標。掌握 C3P0 基礎配置後,建議進一步學習 HikariCP(目前 Spring Boot 2.x 默認連接池,性能更優)、Druid(阿里出品,監控強大)等新一代連接池,根據業務場景選型。