maxPoolSize应按峰值QPS×平均响应时间(秒)×1.5~2估算并向上取整,minIdle宜设为maxPoolSize的1/3~1/2,idleTimeout建议设为数据库wait_timeout的70%~90%。

maxPoolSize 设多少才不拖慢数据库又不浪费内存
它不是越大越好,也不是拍脑袋定个 20 或 100 就完事。真正起作用的是你应用的并发请求峰值和单次 SQL 耗时。比如平均一次查询耗时 50ms,那么单连接每秒最多处理 20 次请求;如果你的 QPS 是 400,理论最小连接数就是 400 / 20 = 20。但得留余量——网络抖动、慢查询、事务嵌套都会吃掉连接。生产环境通常按峰值 QPS × 平均响应时间(秒)× 1.5~2 来估算,再向上取整到 5 的倍数。
常见错误是把 maxPoolSize 设成 200 甚至 500,结果数据库扛不住,报错 Too many connections,或者连接池内部锁争用变高,反而降低吞吐。MySQL 默认 max_connections 常是 151,PostgreSQL 的 max_connections 默认常为 100,别忘了查你的数据库上限。
- Web 应用(Spring Boot + HikariCP):QPS 300、P95 响应 80ms → 建议
maxPoolSize=50起步,压测调优 - 批处理任务混跑时,临时提高
maxPoolSize可行,但必须配connectionTimeout防住长等待 - HikariCP 中该值设为 0 表示无限制(危险!等同于放弃控制)
minIdle 为什么不能等于 maxPoolSize
设成一样看起来“省事”,实际是让连接池失去弹性:空闲连接永远占满,哪怕流量谷底也白占内存、维持 TCP 连接、触发数据库心跳检测。更麻烦的是,某些数据库(如 PostgreSQL)对空闲连接有主动断连机制,minIdle 过高会导致大量 Connection reset by peer 或 broken pipe 错误,而连接池还傻等它恢复。
合理做法是让 minIdle 显著小于 maxPoolSize,一般取后者的 1/3~1/2,且不低于你日常低峰期的稳定并发连接数。HikariCP 默认 minIdle=10,如果你的 maxPoolSize=50,minIdle=15 就比设成 50 更健康。
-
minIdle > 0才能启用连接保活(配合keepaliveTime) - 设为 0 表示“完全懒加载”,首次请求会稍慢,但适合低频后台服务
- Oracle JDBC 驱动在
minIdle=0时可能不触发连接验证,需额外配connectionTestQuery
idleTimeout 到底该设多长:30 秒还是 10 分钟
这个值不是越长越好,也不是越短越安全。它控制的是“一个空闲连接在池里躺多久就该被回收”。设太短(如 30 秒),连接频繁创建销毁,增加数据库 handshake 开销和 GC 压力;设太长(如 10 分钟),可能撞上数据库侧的 wait_timeout(MySQL 默认 8 小时,但很多 DBA 改成 300 秒),导致归还时连接已失效,抛 Connection is closed。
经验做法是:取数据库 wait_timeout 值的 70%~90%,向下取整到分钟级。例如 MySQL wait_timeout=600(10 分钟),那 idleTimeout=540000(9 分钟)就比较稳。HikariCP 默认是 600000(10 分钟),但上线前务必确认数据库配置。
- PostgreSQL 推荐设
idleTimeout=300000(5 分钟),因其tcp_keepalives_idle默认较激进 - 阿里云 RDS MySQL 有些版本默认
wait_timeout=300,此时idleTimeout必须 ≤ 240000(4 分钟) - 该值只对空闲连接生效,正在使用的连接不受影响
HikariCP 和 Druid 在这三个参数上的关键差异
不是所有连接池都叫一个名字,参数行为差得挺远。比如 HikariCP 的 minIdle 是运行时动态维持的下限,而 Druid 的 minIdle 更像初始化时的预热数量,后续未必严格保持;Druid 的 minEvictableIdleTimeMillis 才对应 HikariCP 的 idleTimeout,但前者还受 timeBetweenEvictionRunsMillis 控制扫描频率,后者是连接空闲即计时。
最易踩的坑是照搬配置:把 Druid 的 minIdle=20 直接抄到 HikariCP,却没调 maxPoolSize,结果连接池卡死在 20 不扩容;或者把 HikariCP 的 idleTimeout=600000 塞进 Druid,但忘了 Druid 默认不开启驱逐线程(removeAbandonedOnBorrow=false),等于这参数压根不生效。
- HikariCP:
idleTimeout是硬性超时,单位毫秒;keepaliveTime是保活间隔(需 ≤idleTimeout) - Druid:
minEvictableIdleTimeMillis+timeBetweenEvictionRunsMillis共同决定回收时机 - 两者都不建议在配置里写死数字,用 Spring Boot 的
@ConfigurationProperties绑定,方便不同环境差异化
这三个参数从来不是孤立调的,它们和数据库的 wait_timeout、应用的线程模型、SQL 执行模式(短平快 or 长事务)全绑在一起。漏看任何一个,都可能让连接池从性能加速器变成故障放大器。










