mysql连接卡在sleep状态是因应用未正确关闭连接且服务端wait_timeout与连接池配置不匹配所致;需确保close()调用、max-lifetime

MySQL 连接卡在 sleep 状态不释放,查 show processlist 一堆 Sleep
这是典型的连接未正确关闭 + 服务端超时配置不匹配导致的积压。MySQL 服务端默认 wait_timeout=28800(8 小时),但应用层如果用连接池却从不显式 close() 或没配空闲回收,连接就会一直挂着,直到服务端主动 kill——而这个 kill 恰好发生在你执行下一条语句前,报错 Lost connection to MySQL server during query 或 MySQL server has gone away。
实操建议:
- 先确认当前值:
SHOW VARIABLES LIKE 'wait_timeout';,开发环境可临时调低到60秒快速暴露问题 - 应用代码里所有
Connection、Statement、ResultSet必须在finally或 try-with-resources 中close(),漏一个就可能 leak - 别依赖“连接池会自动清理”——HikariCP 默认
connection-timeout=30000,但空闲连接存活时间由idle-timeout控制,默认 10 分钟,仍远大于常见业务响应时间
HikariCP 的 max-lifetime 和 MySQL wait_timeout 必须错开
如果两者相等或 max-lifetime ≥ wait_timeout,连接池会把一个已被 MySQL 关闭的连接再分配出去,下次使用直接抛异常。这不是 bug,是设计如此:连接池只管“自己没过期”,不管“数据库侧是否还接受它”。
实操建议:
-
max-lifetime必须严格小于wait_timeout,建议留 30–60 秒缓冲,比如 MySQL 设为3600(1 小时),HikariCP 就设3500 - 同时打开
connection-test-query=SELECT 1(MySQL 8.0+ 推荐用isValid())和test-on-borrow=true,但注意这会增加每次获取连接的延迟 - 更轻量的做法是关掉
test-on-borrow,改用keepalive-time=30000(每 30 秒发一次SELECT 1检活),配合validation-timeout=3000
Spring Boot + MyBatis 下,事务未结束就 return 导致连接不归还
常见于 Controller 层直接返回 ResponseEntity<list></list>,但 Service 方法加了 @Transactional,MyBatis 的 SqlSession 绑定在线程上,return 后方法虽结束,事务还没提交/回滚,连接就被卡住——尤其遇到流式查询、分页 count 查询后紧跟 list 查询时特别容易触发。
实操建议:
- 检查所有带
@Transactional的方法,确保没有在事务内提前return或抛出未被捕获的运行时异常(会导致事务回滚但连接不释放) - 避免在事务方法里做 HTTP 调用、文件读写等长耗时操作;若必须,用
@Transactional(propagation = Propagation.REQUIRES_NEW)隔离 - 开启 MyBatis 日志:
logging.level.org.apache.ibatis=DEBUG,观察SqlSessionopen / close 是否成对出现
连接池满但活跃连接数很低,其实是连接被“假占用”
现象是 HikariPool-1 - Pool stats (total=20, active=2, idle=0, waiting=18),但业务明显卡死。这说明连接没真正释放,而是被某个线程阻塞在 I/O 或锁等待中,比如 JDBC 驱动卡在 SocketInputStream.read(),或应用代码里有 synchronized 块包住了数据库操作。
实操建议:
- 用
jstack <pid></pid>抓线程快照,搜索com.mysql.cj和java.net.SocketInputStream,看哪些线程停在 read 上 - 检查是否有慢 SQL 未加索引,导致单次查询 >
connection-timeout,连接卡住后被池标记为“busy”却不释放 - 设置
leak-detection-threshold=60000(单位毫秒),HikariCP 会在连接借用超时后打印堆栈,精准定位哪段代码没 close
最麻烦的情况是连接在 finally 里 close 了,但驱动本身有 bug(如 mysql-connector-java 5.1.47 前的某些版本),升级到 8.0.33+ 或 5.1.49+ 是底线。











