数据库连接池原理与配置
约 2305 字大约 8 分钟
databaseconnection-pool
2025-05-19
数据库连接的创建和销毁是昂贵的操作,涉及 TCP 握手、身份认证、会话初始化等步骤。连接池通过预先创建和复用连接,显著降低延迟和资源消耗。本文深入分析连接池的工作原理,并重点介绍 HikariCP 等主流实现。
为什么需要连接池
连接池生命周期
核心流程
HikariCP 架构
HikariCP 是目前 Java 生态中性能最好的连接池实现,Spring Boot 2.x+ 的默认选择。
HikariCP 快速借用策略
关键优化:
- ThreadLocal 缓存:同一线程优先复用上次使用的连接,减少竞争
- CAS 无锁操作:使用 CAS 而非锁来标记连接状态
- 直接传递(Handoff):归还连接时,如果有等待线程,直接传递而非放回池中
HikariCP 配置
# Spring Boot 配置
spring:
datasource:
hikari:
# 核心参数
maximum-pool-size: 10 # 最大连接数
minimum-idle: 5 # 最小空闲连接
connection-timeout: 30000 # 获取连接超时(ms)
idle-timeout: 600000 # 空闲连接超时(ms), 10 分钟
max-lifetime: 1800000 # 连接最大生命周期(ms), 30 分钟
keepalive-time: 30000 # 保活间隔(ms), 30 秒
# 连接验证
connection-test-query: SELECT 1 # 验证查询(JDBC4 驱动不需要)
validation-timeout: 5000 # 验证超时(ms)
# 泄漏检测
leak-detection-threshold: 60000 # 连接借出超过 60 秒报警
# 连接属性
pool-name: MyAppPool
auto-commit: true
connection-init-sql: SET NAMES utf8mb4// 编程方式配置
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);
config.setMinimumIdle(5);
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
// 性能优化参数
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("useServerPrepStmts", "true");
HikariDataSource ds = new HikariDataSource(config);连接验证
验证策略
| 策略 | 说明 | 推荐 |
|---|---|---|
| 借出时验证 | 每次借出前验证连接有效性 | 延迟增加,不推荐 |
| 归还时验证 | 归还时验证 | 不推荐 |
| 空闲时验证 | 定期检查空闲连接 | 推荐(HikariCP 默认) |
| 无验证 | 依赖 max-lifetime 和 keepalive | 结合使用 |
为什么需要 max-lifetime
- 数据库/防火墙可能有连接超时设置
- 长期连接可能积累资源泄漏
- 保证连接的"新鲜度"
- max-lifetime 应比数据库的
wait_timeout至少少 30 秒
-- MySQL 查看连接超时
SHOW VARIABLES LIKE 'wait_timeout';
-- 默认 28800 (8 小时)
-- 建议: max-lifetime = wait_timeout - 30s
-- 即 max-lifetime = 28770000 (ms)泄漏检测
连接泄漏是指应用借出连接后未归还(忘记 close),导致连接池逐渐耗尽。
// HikariCP 泄漏检测
config.setLeakDetectionThreshold(60000); // 借出超过 60 秒打印警告
// 泄漏警告日志示例
// WARN HikariPool-1 - Connection leak detection triggered for connection
// java.lang.Exception: Apparent connection leak detected
// at com.example.UserService.getUser(UserService.java:45)
// at com.example.UserController.handle(UserController.java:20)连接池大小公式
经典公式
连接数 = (核心数 × 2) + 有效磁盘数对于 SSD(无旋转延迟):
连接数 ≈ 核心数 × 2 + 1例如:4 核 CPU → 4 × 2 + 1 = 9 个连接
实际调优步骤
主流连接池对比
| 特性 | HikariCP | Druid | DBCP2 | C3P0 |
|---|---|---|---|---|
| 性能 | 最高 | 高 | 中等 | 较低 |
| Spring Boot 默认 | 是(2.x+) | 否 | 否 | 否 |
| 监控 | JMX/Micrometer | 内置 Web 监控面板 | JMX | JMX |
| SQL 防火墙 | 无 | 内置 | 无 | 无 |
| 连接泄漏检测 | 有 | 有 | 有 | 有 |
| 慢 SQL 监控 | 无 | 内置 | 无 | 无 |
| 代码量 | ~3000 行 | ~100000 行 | 中等 | 中等 |
| 社区活跃度 | 高 | 高(阿里) | 中 | 低(停止维护) |
Druid 特色功能
# Druid 配置示例
spring:
datasource:
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
# 内置监控
stat-view-servlet:
enabled: true
url-pattern: /druid/*
# SQL 防火墙
filter:
wall:
enabled: true
config:
drop-table-allow: false
delete-where-none-check: true
# 慢 SQL 监控
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000配置最佳实践
HikariCP 生产配置
spring:
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 10 # 建议等于 maximum-pool-size(固定大小池)
connection-timeout: 30000
idle-timeout: 0 # 固定大小池时设为 0
max-lifetime: 1770000 # 数据库 wait_timeout - 30s
keepalive-time: 30000
leak-detection-threshold: 60000
pool-name: MyApp-HikariPool关键原则
监控指标
// HikariCP 暴露的 MBean/Metrics
// HikariPool-1.pool.ActiveConnections — 活跃连接数
// HikariPool-1.pool.IdleConnections — 空闲连接数
// HikariPool-1.pool.TotalConnections — 总连接数
// HikariPool-1.pool.PendingThreads — 等待连接的线程数 (重要!)
// HikariPool-1.pool.ConnectionTimeout — 连接超时次数
// HikariPool-1.pool.ConnectionCreated — 创建连接次数
// HikariPool-1.pool.ConnectionAcquired — 借出连接次数
// HikariPool-1.pool.ConnectionUsage — 连接使用时长分布
// Spring Boot Actuator + Micrometer
// /actuator/metrics/hikaricp.connections.active
// /actuator/metrics/hikaricp.connections.idle
// /actuator/metrics/hikaricp.connections.pending| 指标 | 正常范围 | 异常说明 |
|---|---|---|
| PendingThreads | 0 | >0 说明连接不够或有慢查询 |
| ActiveConnections | < 80% max | 接近 max 说明负载高 |
| ConnectionTimeout | 0 | >0 说明获取连接超时 |
| ConnectionUsage p99 | < 100ms | 过高说明事务/查询太慢 |
总结
- 连接池通过复用连接避免了昂贵的创建/销毁开销
- HikariCP 凭借 ConcurrentBag + ThreadLocal + CAS 实现了极高的并发性能
- 连接池大小遵循
CPU核数 × 2 + 1的经验公式,宁小勿大 max-lifetime必须小于数据库的连接超时设置- 开启泄漏检测和 keepalive 提升连接池的可靠性
- 监控 PendingThreads 和 ConnectionTimeout 是发现问题的关键
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于