事务无法提交的根本原因是连接耗尽而非事务阻塞,需先释放僵尸连接(如KILL Sleep线程)、临时调高max_connections应急,并永久协同调优数据库max_connections、wait_timeout及应用连接池配置,严防连接泄漏。

事务无法提交不是因为事务本身卡住,而是它拿不到连接——max_connections 耗尽后,连 BEGIN 都失败,更别说 COMMIT 或 ROLLBACK。必须先释放连接资源,再确保后续事务能稳定获取连接。
为什么事务卡在“未提交”状态却报 too many connections
这不是事务阻塞了连接,而是连接池/应用层已无可用连接可分配给新事务。常见现象包括:
- 日志里反复出现
error 1040 (hy000): too many connections,但SHOW PROCESSLIST显示大量Sleep状态连接(即空闲但未关闭) -
threads_connected接近max_connections,而threads_running却很低(说明连接被占着不用) - 应用端抛出连接超时异常,但数据库里查不到正在执行的长事务
根本原因是:连接泄漏(没调 close())、空闲连接回收太慢(wait_timeout 过大)、或连接池配置远超 MySQL 承载能力。
临时救急:快速释放僵尸连接
当服务已不可用,优先清空无效连接,让关键事务能抢到资源:
- 登录 MySQL,执行
KILL命令干掉长时间Sleep的连接:KILL <thread_id>;
(先用SHOW PROCESSLIST;查 ID) - 批量杀掉空闲超 60 秒的连接(谨慎执行):
SELECT CONCAT('KILL ',id,';') FROM information_schema.processlist WHERE COMMAND = 'Sleep' AND TIME > 60;复制结果再执行 - 临时提升连接上限(仅限应急):
SET GLOBAL max_connections = 800;(重启失效,但能争取修复时间)
注意:KILL 不会中断正在执行的 SQL,只对 Sleep 或等待锁的连接有效;若存在真正在跑的慢查询,需单独优化 SQL 或加索引。
永久修复:max_connections 与连接池必须协同调优
单独调高 max_connections 是饮鸩止渴——每个连接吃 2–4MB 内存,设成 2000 可能直接触发 OOM。必须同步约束应用侧连接用量:
-
max_connections推荐值按服务器内存算:32GB 机器建议设为 1000~1200,16GB 机器 600~800,且必须配合wait_timeout = 60(秒)和interactive_timeout = 60(避免空闲连接赖着不走) - 连接池最大值(如 HikariCP 的
maximum-pool-size)不能超过max_connections的 70%,例如 MySQL 设了 800,池子最多配 560 - 必须启用连接泄漏检测:
leak-detection-threshold=60000(毫秒),超 60 秒未归还就报 warn,方便定位代码里漏关连接的位置
Java 中最常漏关的是 ResultSet 和 Statement,Python 里是没用 with 上下文管理器,这些都得代码层兜底。
事务提交失败的真正瓶颈往往不在数据库侧
很多团队盯着 max_connections 调参,却忽略应用层并发控制。比如一个微服务实例开 50 个线程,每个线程都配了独立连接池(最大 20),10 个实例瞬间打满 1000 连接。这种架构下,调参毫无意义。
真正要做的:在网关层做请求限流(如令牌桶),在服务内做连接池共享(别每个线程建一个池),并强制所有事务设置 timeout(Spring 的 @Transactional(timeout = 5))。否则,一个卡住的事务就能拖垮整条链路。


















