MySQL事务不释放本质是连接长期占用未提交/回滚,导致锁阻塞;需通过SHOW PROCESSLIST、INNODB_TRX等实时诊断,HikariCP的max-lifetime须小于wait_timeout,并禁用test-on-borrow改用keepalive探活;Spring事务中提前return会导致SqlSession绑定线程不释放,应收窄事务边界或确保完整执行。

MySQL 本身不“知道”你用的是连接池,也不会主动干预事务状态;所谓“事务不释放”,本质是连接被长期占用、未提交/回滚,而该连接又没被应用层正确关闭或归还——此时 MySQL 只能干等,直到 wait_timeout 或 interactive_timeout 到期强制断开,但这个过程可能长达数小时,期间连接卡在 Sleep 状态,事务锁未释放,阻塞其他操作。
确认是不是连接池泄露引发的事务卡住
别猜,先查 MySQL 实时状态:
- 执行
SHOW PROCESSLIST;,重点看Command列为Sleep、Time值远超业务正常响应时间(比如 > 300 秒)的连接,再结合Info列是否为空——空值 + 高 Time 是典型泄漏信号 - 执行
SELECT * FROM information_schema.INNODB_TRX\G,检查TRX_STATE是否有大量RUNNING或LOCK WAIT,且TRX_STARTED时间异常久远 - 对比
SHOW STATUS LIKE 'Threads_connected';在低峰/高峰的差值,如果持续攀升不回落,基本可锁定泄漏
HikariCP 配置必须错开 max-lifetime 和 wait_timeout
这是最容易被忽略的硬性约束:HikariCP 的 max-lifetime 必须严格小于 MySQL 的 wait_timeout,否则连接池会把一个 MySQL 已经关闭的连接再分配出去,下一次 executeQuery() 直接抛 CommunicationsException。
- 查 MySQL 当前值:
SHOW VARIABLES LIKE 'wait_timeout';(默认 28800 秒,即 8 小时) - 设 HikariCP 的
max-lifetime为wait_timeout - 60,例如 MySQL 设为 3600(1 小时),HikariCP 就配3540 - 同时设
idle-timeout≤max-lifetime,避免空闲连接比活跃连接活得还久 - 禁用
test-on-borrow(增加延迟),改用keepalive-time=30000+validation-timeout=3000,每 30 秒探活一次
Spring Boot + MyBatis 下事务提前 return 导致连接卡死
这不是连接池配置问题,而是 Spring 事务传播机制和资源绑定逻辑导致的:@Transactional 方法里 Controller 直接 return ResponseEntity.of(...),方法虽退出,但事务未提交,MyBatis 的 SqlSession 仍绑在当前线程上,连接无法归还。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 检查所有带
@Transactional的 Service 方法,确认没有在事务块内return、throw new RuntimeException()未捕获、或调用阻塞式外部服务(如 HTTP)后中断流程 - 分页场景特别危险:先执行
count查询(触发事务开启),紧接着list查询,若中间return,整个事务上下文就悬停了 - 修复方式:把事务边界收窄,用
@Transactional(propagation = Propagation.REQUIRES_NEW)隔离非核心逻辑;或确保事务方法体完整执行到 commit/rollback
开发环境快速暴露问题的 wait_timeout 设置
生产环境不能乱调 wait_timeout,但开发/测试环境可以主动激进一点,让泄漏立刻现形:
- MySQL 端执行:
SET GLOBAL wait_timeout = 60;(注意:需 SUPER 权限,且只对新连接生效) - 配合 HikariCP 开启泄漏检测:
leak-detection-threshold=60000,超 60 秒未 close 就打印堆栈 - 观察日志里是否频繁出现 “Connection leak detection triggered” 或 “Connection has been abandoned” 类提示
- 上线前务必改回合理值(如 3600),否则长事务会直接被 MySQL 断连
真正难处理的不是参数怎么设,而是那些藏在 try-catch 里没进 finally、被 ThreadLocal 持有、或被流式查询(StreamingResultSet)意外延长生命周期的连接——它们不会报错,只会悄悄堆积,直到某天凌晨三点数据库连不上。










