MySQL 5.7 的订单库报 Lock wait timeout exceeded; try restarting transaction,一条按主键更新的语句等了五十秒才失败,业务侧看到的是下单接口超时。
这类报错背后常见的原因有几处,逐个排除就行。另一个事务拿着同一行的排他锁一直没提交,连接池里还挂着空闲事务;更新条件没走索引,InnoDB 把间隙锁的范围放大了好几倍;隔离级别是 RR,间隙锁把相邻区间也锁住,插入被挡住;应用层开了事务却在中途做了远程调用,锁持有时间被拉长。
上来先看谁在等锁、谁在持锁
mysql -e "select * from information_schema.innodb_lock_waits\G"
然后查当前长事务和空闲事务
mysql -e "select trx_id,trx_state,trx_started,trx_mysql_thread_id from information_schema.innodb_trx order by trx_started"
随后把超过阈值的空闲事务杀掉
mysql -e "select concat('kill ',trx_mysql_thread_id,';') from information_schema.innodb_trx where trx_started < now() - interval 60 second"
等前面都确认过,再确认索引和执行计划是否合理
mysql -e "explain update orders set status=1 where order_no='A1001'"
改完先别撤,确认这几项。innodb_lock_waits 里不再有等待记录,同一条更新在毫秒级返回,innodb_trx 里没有超过一分钟的事务。
提醒一点。锁等待多半是事务太长,不是数据库慢;把事务里的远程调用挪出去,并给更新条件补上索引,比调大 innodb_lock_wait_timeout 有用得多。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。
