应先定位锁等待源头而非调参:通过INFORMATION_SCHEMA.INNODB_TRX查LOCK WAIT事务,INNODB_LOCK_WAITS查阻塞关系,INNODB_LOCKS查具体行锁,再结合线程ID定位肇事SQL。
查清谁在堵路:快速定位锁等待源头
出现 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction,第一反应不该是调参数,而是看“谁卡住了谁”。InnoDB 的锁等待现场稍纵即逝,必须用系统视图抓实时快照:
-
SELECT * FROM information_schema.INNODB_TRX—— 查当前所有活跃事务,重点关注trx_state = 'LOCK WAIT'和trx_started时间过长的 -
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS—— 直接给出等待关系:blocking_trx_id是肇事者,requested_lock_id是受害者 -
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS—— 查具体锁在哪行(lock_trx_id、lock_rec_id),配合INNODB_TRX中的trx_mysql_thread_id就能定位到线程
别依赖 SHOW PROCESSLIST,它只显示连接状态,不反映行级锁关系;也别等错误日志里出现 SQL 再查——那时锁可能早已释放。
临时止血:调整 innodb_lock_wait_timeout 参数
这个参数不是“治本”,但能避免业务雪崩。默认 50 秒太长,高并发接口常等几十秒才报错,用户体验极差;设太短(如 1 秒)又容易误杀正常慢事务。建议按场景分级设置:
- 线上核心接口:设为
5或10秒,让失败更快暴露,前端可降级或重试 - 后台批处理作业:可设为
120,但必须确保事务本身不超时(比如避免在事务里调外部 HTTP) - 修改方式分两种:
SET innodb_lock_wait_timeout = 10只对当前会话生效;SET GLOBAL innodb_lock_wait_timeout = 10对新连接生效,**当前已连的连接不会变**,这点极易踩坑 - 永久生效要改配置文件(如
/etc/my.cnf),加一行innodb_lock_wait_timeout = 10,然后重启 MySQL —— 但生产环境未必允许重启
根因排查:为什么锁等这么久?
调参只是缓冲,真正要盯的是锁为啥不释放。常见硬伤有三个: