MySQL 5.7 上一批订单接口报 Lock wait timeout exceeded,DBA 连上去 SHOW PROCESSLIST 只看到正常的查询,information_schema.innodb_trx 里也只有当前会话,过一会儿又自己好了。
一开始怀疑是「有长事务一直没提交,锁被攥在另一个库的会话上」,查了一圈,方向不对。
真正麻烦的地方在于,几个原因的现象几乎一样。持锁的事务已经提交但连接还在,processlist 里看着只是 Sleep。少数情况下是锁等待发生在存储引擎层,processlist 不展示等待中的普通请求。
不容易想到的是,autocommit 关着,代码里的 SELECT 也把行锁住了。
直接查正在等锁和持锁的事务
mysql -e 'SELECT * FROM information_schema.innodb_trx ORDER BY trx_started'
再往下看锁等待的具体对象
mysql -e 'SELECT * FROM performance_schema.data_lock_waits'
接着找出长事务并决定是否终止
mysql -e 'SELECT trx_id,trx_started,trx_mysql_thread_id FROM information_schema.innodb_trx'
杀掉长事务的会话释放锁
mysql -e 'KILL 12345'
别只看报错消失,验证要多做一步。innodb_trx 里没有超过 60 秒的事务,业务接口不再报 Lock wait timeout,锁等待次数降为个位数。
补一句。KILL 会话要确认它没在做大批量写入,否则回滚时间可能比等待更久;长事务最好从代码的提交时机上解决。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
