C3P0 是開源 JDBC 連線池,實作 DataSource 與 JNDI 綁定,支援 JDBC3 規格,廣泛用於 Hibernate、Spring 專案。本文以「大水池養魚」比喻連線池,從零建立 Maven 專案,示範**程式碼配置**與**外部屬性檔配置**兩種方式完整查詢流程。
<dependencies> <dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version></dependency> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency> </dependencies>
CREATE DATABASE test DEFAULT CHARSET utf8; USE test; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, user_name VARCHAR(20), password VARCHAR(100), address VARCHAR(100), phone_number VARCHAR(20), create_time DATETIME, update_time DATETIME ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user VALUES (1,'test','pwd','addr','123',NOW(),NOW()),(2,'te2','pwd','addr2','456',NOW(),NOW());
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 demo;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import org.junit.Test;
public class C3p0Demo1 {
@Test
public void testManualConfig() throws Exception {
// 1. 讀取屬性檔
Properties prop = new Properties();
try (InputStream in = getClass().getClassLoader().getResourceAsStream("db.properties")) {
prop.load(in);
}
// 2. 建立並配置 DataSource
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(prop.getProperty("jdbc.driver"));
ds.setJdbcUrl(prop.getProperty("jdbc.url"));
ds.setUser(prop.getProperty("jdbc.username"));
ds.setPassword(prop.getProperty("jdbc.password"));
// 可選調優參數
ds.setInitialPoolSize(5);
ds.setMinPoolSize(5);
ds.setMaxPoolSize(20);
ds.setMaxIdleTime(300);
// 3. 取得連線、查詢、關閉(歸還池中)
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user");
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.printf("id=%s, name=%s, phone=%s, create=%s%n",
rs.getInt("id"), rs.getString("user_name"), rs.getString("phone_number"), rs.getTimestamp("create_time"));
}
} // try-with-resources 自動關閉 rs/ps/conn(歸還連線池)
ds.close(); // 應用關閉時釋放池資源
}
}
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=300
package demo;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.*;
import org.junit.Test;
public class C3p0Demo2 {
@Test
public void testAutoConfig() 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()) {
while (rs.next()) {
System.out.printf("id=%s, name=%s%n", rs.getInt("id"), rs.getString("user_name"));
}
}
// DataSource 介面無 close(),若需關閉池需轉型
((ComboPooledDataSource) ds).close();
}
}
Connection.close() 在連線池中**不是真正關閉**,而是**歸還連線**給池中供下次重用。initialPoolSize 啟動預熱、maxPoolSize 防止連線風暴、maxIdleTime 回收閒置連線。preferredTestQuery、idleConnectionTestPeriod 定期驗證連線有效性。com.mysql.cj.jdbc.Driver,舊版 com.mysql.jdbc.Driver 已棄用。useSSL=false&serverTimezone=UTC 避免時區/SSL 警告。c3p0.properties 檔名**固定**,不可自訂;若需多環境請用方式一程式碼區分。