Java 使用 C3P0 数据库连接池,并测试 minPoolSize
和 maxPoolSize
的设置。并测试超出连接池的最大连接数的情况。
依赖配置
<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>
</dependencies>
Java实现代码
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.management.C3P0Registry;
import com.mchange.v2.c3p0.management.ActiveManagementCoordinator;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class C3P0ConnectionTest {
// 创建 C3P0 数据源实例
private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
public static void main(String[] args) throws PropertyVetoException, InterruptedException {
// 配置 C3P0 数据源参数
configureDataSource();
// 开启线程实时打印连接池状态
startConnectionPoolMonitoring();
// 模拟连接数不足的测试场景
simulateConnectionUsage();
}
// 配置 C3P0 数据源的参数
private static void configureDataSource() throws PropertyVetoException {
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver"); // MySQL 驱动
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test_db"); // 数据库 URL
dataSource.setUser("root"); // 数据库用户名
dataSource.setPassword("password"); // 数据库密码
// 配置 C3P0 的核心参数
dataSource.setInitialPoolSize(5); // 初始连接数
dataSource.setMinPoolSize(5); // 最小连接数
dataSource.setMaxPoolSize(10); // 最大连接数
dataSource.setMaxIdleTime(300); // 空闲连接的最大存活时间(秒)
dataSource.setAcquireIncrement(2); // 当连接池耗尽时,每次尝试增长的连接数
dataSource.setMaxStatements(50); // 最大缓存的 SQL 语句数量
dataSource.setCheckoutTimeout(2000); // 获取连接的超时时间(毫秒)
dataSource.setTestConnectionOnCheckout(true); // 获取连接时检测其有效性
}
// 模拟使用连接的场景,测试连接数不足的报错
private static void simulateConnectionUsage() {
List<Connection> connections = new ArrayList<>();
try {
System.out.println("开始模拟数据库连接使用...");
for (int i = 1; i <= 15; i++) { // 尝试超出最大连接数
System.out.println("尝试获取第 " + i + " 个连接...");
Connection connection = dataSource.getConnection();
connections.add(connection); // 保存连接以防止被释放
System.out.println("成功获取第 " + i + " 个连接");
Thread.sleep(2000); // 模拟连接占用时间
}
} catch (SQLException e) {
System.err.println("连接数不足,无法获取更多连接!");
e.printStackTrace();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 释放所有连接
for (Connection conn : connections) {
try {
if (conn != null && !conn.isClosed()) {
conn.close();
System.out.println("连接已释放");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
// 开启线程,实时监控连接池状态
private static void startConnectionPoolMonitoring() {
new Thread(() -> {
while (true) {
try {
// 获取连接池的运行时状态
int totalConnections = dataSource.getNumConnectionsDefaultUser();
int busyConnections = dataSource.getNumBusyConnectionsDefaultUser();
int idleConnections = dataSource.getNumIdleConnectionsDefaultUser();
// 打印连接池的实时状态
System.out.println("\n[连接池状态]");
System.out.println("总连接数: " + totalConnections);
System.out.println("使用中的连接数: " + busyConnections);
System.out.println("空闲连接数: " + idleConnections);
Thread.sleep(2000); // 每 2 秒打印一次
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
输出
-
正常连接使用
[连接池状态] 总连接数: 5 使用中的连接数: 3 空闲连接数: 2
-
连接数耗尽报错
尝试获取第 11 个连接... 连接数不足,无法获取更多连接! com.mchange.v2.resourcepool.CannotAcquireResourceException: A resource pool could not acquire a resource ...
-
释放连接后连接池恢复
[连接池状态] 总连接数: 5 使用中的连接数: 0 空闲连接数: 5
注意
- 根据实际情况调整
maxPoolSize
和acquireIncrement
参数,避免频繁的连接创建和销毁。 - 如果数据库连接数不足,检查数据库的
max_connections
配置是否满足需求。