MySQL 5.7.18中INSERT语句未触发锁等待超时问题求助
结合你的MySQL版本、配置和场景,我来拆解一下可能的原因:
首先明确核心场景
你用的是MySQL 5.7.18 + InnoDB,已经把innodb_lock_wait_timeout设为300秒(5分钟),隔离级别是READ_COMMITTED。事务1持有Users表ID=1行的X锁,事务2插入关联该用户的Purchases记录时,需要获取Users对应行的S锁,但等了超过5分钟都没触发超时。
最可能的几个原因及排查步骤
1. 锁超时参数根本没生效
这是最常见的坑——你以为设置了innodb_lock_wait_timeout,但实际上参数没作用到当前会话或全局。
赶紧在事务2的那个会话里执行这条命令,确认实际值:
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
如果返回的不是300,那问题就出在这:
- 如果你是用
SET innodb_lock_wait_timeout=300;设置的,得确保是在事务2的会话里执行的(会话级设置只对当前连接生效); - 如果是改了my.cnf/my.ini但没重启MySQL,全局参数不会生效,要么重启服务,要么执行
SET GLOBAL innodb_lock_wait_timeout=300;(新连接才会用这个值)。
另外别搞混:lock_wait_timeout是给MyISAM用的锁超时参数,和InnoDB完全没关系,别设错参数了。
2. MySQL 5.7.18的已知Bug
在MySQL 5.7的早期版本(包括你用的5.7.18)里,存在一个外键检查时锁等待不触发超时的Bug。当INSERT/UPDATE涉及外键验证时,InnoDB在等待父表行锁的过程中,不会正确应用innodb_lock_wait_timeout的设置,导致等待无限期进行。
这个问题在后续的5.7版本(比如5.7.20及以后)已经被修复了。如果前面确认参数是对的,那大概率是这个Bug在搞鬼,建议你升级到5.7的最新稳定版本(比如5.7.44)。
3. 等待的不是锁?
从你的PROCESSLIST结果看,事务2的状态是update,但你执行的是INSERT——这是因为InnoDB处理外键插入时,内部会触发对父表的检查操作,状态会被标记成update。但你得确认这真的是锁等待:
执行这条命令看看当前的锁等待情况:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
如果结果是空的,说明事务2的等待不是锁等待,可能是磁盘IO慢、其他资源竞争之类的问题;如果有结果,那确实是锁等待,回到前面两个原因排查。
解决建议
- 先确认事务2会话里的
innodb_lock_wait_timeout是不是真的是300; - 用
INNODB_LOCK_WAITS验证锁等待的存在; - 如果参数没问题,优先升级MySQL 5.7到最新稳定版,修复Bug;
- 临时应急:可以手动KILL掉事务2的进程,或者调整业务逻辑,别让事务1长时间持有父表的行锁。
内容的提问来源于stack exchange,提问作者CrazyMinion

