mysql连接池最大连接数应设为200–500,服务端max_connections不建议超1000,应用层hikaricp maximumpoolsize设为dba允许值的60%~70%,并需合理配置connectiontimeout、idletimeout等参数,避免连接泄露、事务未释放及读写分离路由不当导致的连接耗尽。

MySQL 连接池最大连接数设多少才不翻车
盲目调高 max_connections 不但不能提升吞吐,反而会因线程竞争、内存耗尽导致 MySQL 崩溃。真实压测中,多数业务在 200–500 之间就遇到瓶颈,关键不在“能开多少”,而在“有多少连接真正在干活”。
- 先查当前活跃连接:
SHOW STATUS LIKE 'Threads_connected';
和SHOW STATUS LIKE 'Threads_running';
—— 后者才是正在执行 SQL 的线程,它长期 > 50 就说明查询慢或锁等待严重 - 应用层连接池(如 HikariCP)的
maximumPoolSize建议设为 DBA 允许的max_connections的 60%~70%,留出空间给后台任务、监控、DBA 操作 - MySQL 服务端的
max_connections不建议超过1000(尤其在 8GB 内存以下机器),每连接默认占用约 2MB 内存,超了直接 OOM
HikariCP 关键参数怎么配才不拖慢请求
HikariCP 不是设了 maximumPoolSize 就万事大吉,几个隐藏坑点常让高并发下连接获取超时或空转。
-
connectionTimeout必须显式设(如3000),否则默认 30 秒——用户等半分钟才报错,体验极差 -
idleTimeout建议设为600000(10 分钟),太短会导致频繁销毁重建连接;但若后端 MySQL 开了wait_timeout=60,必须让idleTimeout小于它,否则连接被服务端主动断开后,HikariCP 不知道,下次取出来直接报Connection closed -
leakDetectionThreshold设成60000(60 秒),能抓到没 close() 的 Connection,避免连接泄露把池子占满 - 禁用
testOnBorrow(已废弃),改用connectionTestQuery=SELECT 1+validationTimeout=3000,避免每次取连接都执行校验拖慢响应
事务边界不清导致连接池卡死的真实案例
高并发下最常见“连接池耗尽”不是因为 QPS 高,而是事务没及时结束,连接被长期占用。典型表现:Threads_running 低,但 HikariCP 的 active 连接数持续接近 maximumPoolSize,且 pending 队列不断增长。
- Spring Boot 中 @Transactional 注解方法若抛出非 RuntimeException(如 checked exception),事务默认不回滚,连接也不会释放——务必确认
@Transactional(rollbackFor = Exception.class) - 流式查询(
ResultSet.TYPE_FORWARD_ONLY)未关闭ResultSet或Statement,连接无法归还,HikariCP 日志会出现Connection marked as broken because of an exception - 异步任务(@Async)里开启事务,容易脱离原始请求生命周期,连接在异步线程结束后才释放,造成“连接幽灵占用”
读写分离 + 连接池分组的实际落地要点
单主多从架构下,把所有流量打向主库,连接池再优化也扛不住写请求激增。分组连接池不是简单配两个 HikariDataSource,而是要和路由逻辑对齐。
- 主库连接池
maximumPoolSize可设小些(如 30),从库池可稍大(如 80),因为读请求通常更多、更轻量 - 避免在 DAO 层硬编码
slaveDataSource,用 AbstractRoutingDataSource + ThreadLocal 路由,但注意 Spring 的事务传播机制:如果一个 @Transactional 方法里先查后写,必须强制走主库,否则从库查到的是旧数据 - 从库延迟监控必须做——当
Seconds_Behind_Master > 30时,自动将该从库连接池setIsReadOnly(false)或临时剔除,否则读到脏数据比慢还致命
Threads_running 和 HikariCP 的 active/pending 指标,比背参数重要得多。










