MySQL数据库连接池耗尽是后端服务运行中常见的故障场景,当应用申请的数据库连接数超过连接池的最大限制,且没有可用连接释放时,就会出现获取连接超时、接口报错等问题。HikariCP凭借轻量、高性能的特性,成为Java生态中主流的连接池选择,合理的配置和调优是避免连接池耗尽的核心手段。

连接池耗尽的常见表现与原因
连接池耗尽时,应用通常会抛出类似Connection_is_not_available或者Timeout_waiting_for_connection的异常,接口响应时间会明显上升,严重时会导致服务不可用。常见的原因主要有以下几类:
- 连接池最大连接数配置过小,无法支撑当前业务的并发请求量
- 存在连接泄漏问题,即获取连接后没有正确关闭,导致连接一直被占用无法回收
- 数据库本身性能瓶颈,查询执行时间过长,连接占用时间超出预期
- 突发流量导致短时间内连接申请量激增,超过连接池的处理能力
HikariCP核心参数与连接数调优
HikariCP的参数配置直接决定了连接池的行为,合理的参数设置是避免耗尽的基础。以下是和连接数相关的核心参数说明:
| 参数名 | 默认值 | 参数说明 |
|---|---|---|
| maximumPoolSize | 10 | 连接池能维护的最大连接数,包括空闲和正在使用的连接 |
| minimumIdle | 和maximumPoolSize一致 | 连接池维护的最小空闲连接数 |
| connectionTimeout | 30000 | 从连接池获取连接的最大等待时间,单位毫秒 |
| idleTimeout | 600000 | 空闲连接的最大存活时间,超过该时间会被回收,单位毫秒 |
| maxLifetime | 1800000 | 连接的最大生命周期,无论是否空闲,超过该时间会被回收,单位毫秒 |
最大连接数的合理设置
maximumPoolSize不是越大越好,需要结合MySQL的最大连接数限制和业务并发量来设置。首先需要确认MySQL本身的最大连接数配置:
-- 查看MySQL当前最大连接数配置 SHOW VARIABLES LIKE 'max_connections'; -- 临时调整最大连接数,重启后失效 SET GLOBAL max_connections = 200;
一般建议HikariCP的maximumPoolSize设置为MySQL的max_connections的70%到80%,同时需要结合应用的单机QPS和单个请求的数据库平均耗时计算:假设单个请求平均占用连接100ms,单机QPS为100,那么需要的连接数大概是100 * 0.1 = 10,再预留一定的冗余空间即可。
其他关键参数的调优建议
minimumIdle建议设置为和maximumPoolSize一致,避免频繁创建和销毁连接带来的性能开销,除非是连接数波动非常大的场景。connectionTimeout建议设置为业务能接受的最大等待时间,通常设置为3000到5000毫秒即可,避免等待时间过长导致请求堆积。idleTimeout和maxLifetime需要小于MySQL的wait_timeout配置,避免连接被数据库主动关闭后,连接池还持有无效连接。
连接泄漏的排查与解决
连接泄漏是连接池耗尽的另一个常见原因,即代码中获取连接后没有正确释放。HikariCP提供了连接泄漏检测的功能,只需要配置leakDetectionThreshold参数即可,该参数表示连接被借出后超过该时间没有被归还,就会打印泄漏日志,单位毫秒。
配置示例:
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class DataSourceConfig {
public HikariDataSource hikariDataSource() {
HikariConfig config = new HikariConfig();
// MySQL连接基础配置
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=utf8");
config.setUsername("root");
config.setPassword("123456");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
// 连接池核心参数
config.setMaximumPoolSize(20);
config.setMinimumIdle(20);
config.setConnectionTimeout(3000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
// 连接泄漏检测阈值,设置为2000毫秒,超过2秒未归还连接会打印日志
config.setLeakDetectionThreshold(2000);
return new HikariDataSource(config);
}
}
当出现连接泄漏日志时,需要根据日志中的堆栈信息定位到未正确关闭连接的代码,确保所有数据库操作都在try-with-resources块中执行,避免手动关闭连接遗漏:
// 正确的连接使用方式,try-with-resources会自动关闭连接
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE id = ?")) {
ps.setInt(1, 1);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getString("name"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
突发流量场景的应对方案
如果是突发流量导致的连接池耗尽,除了调整连接池参数,还可以结合以下方案应对:
- 对数据库操作做限流,避免短时间大量请求同时申请连接
- 优化慢查询,减少单个连接的占用时间,提升连接周转率
- 引入读写分离,将读请求分流到从库,降低主库的连接压力
- 对非核心的数据库操作做异步处理,避免同步占用连接
调优后的验证方法
调优完成后,可以通过以下方式验证效果:
- 监控HikariCP的连接池指标,包括活跃连接数、空闲连接数、等待连接数,确认指标在正常范围内
- 模拟高并发场景压测,观察是否还会出现连接获取超时的异常
- 持续观察应用的错误日志,确认没有连接池相关的报错
通过以上HikariCP参数调优、连接泄漏排查、流量应对的组合方案,可以有效解决MySQL数据库连接池耗尽的问题,保障应用的稳定运行。