锁超时错误表现为“Lock wait timeout exceeded; try restarting transaction”,是事务等待锁超时被强制终止,非死锁;常见于多行更新或长事务交叉场景,如报表导出时用户下单。

锁超时错误长什么样?先确认是不是它
看到 Lock wait timeout exceeded; try restarting transaction 这个错误,基本就是 innodb_lock_wait_timeout 生效了——不是死锁,而是某个事务等锁太久被强制踢出。常见于 UPDATE/DELETE 涉及多行、或和长事务交叉的场景,比如报表导出期间用户还在下单。
调整 innodb_lock_wait_timeout 值前必须搞清的事
这个参数只控制「等待锁的最长时间」,不解决锁本身;盲目调大可能让问题更隐蔽,比如把 50 个并发卡住的事务拖成 120 秒才报错,反而压垮连接池。
-
innodb_lock_wait_timeout是会话级变量,可动态设,但全局修改需写进配置文件(如/etc/my.cnf的[mysqld]段) - 默认值是 50 秒,线上建议先观察:用
SELECT * FROM information_schema.INNODB_TRX查当前持锁/等锁事务,看平均等待是否真接近 50 - 应用层有重试逻辑的话,调到 30~60 是安全范围;若没重试,调太大等于掩盖问题
- 注意和应用连接池的
socketTimeout或queryTimeout对齐,避免 MySQL 没超时但客户端先断了
真正该优先查的三类锁源头
调参是下策,锁争抢才是病根。以下情况比改 timeout 更有效:
- 缺失索引导致 UPDATE 全表扫描:检查执行计划里有没有
type: ALL,对 WHERE 条件字段补上复合索引 - 事务包太大:比如一个事务里先查再更新再插入日志,应拆成小事务,或把非核心操作(如日志记录)挪到事务外
- 长事务未提交:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60找出运行超 1 分钟的事务,定位对应应用代码
临时应急与长期稳定的区别处理
上线紧急时可快速缓解,但不能替代治理:
- 会话级临时调:执行
SET innodb_lock_wait_timeout = 30,仅对当前连接生效,适合排查单条慢 SQL - 全局改配置:在
my.cnf加innodb_lock_wait_timeout = 30,重启生效,适合已确认等待普遍偏长且应用能兜底重试 - 永远别设成 0:表示无限等待,极易引发连接堆积,MySQL 官方文档明确不推荐
- 配合监控:把
Innodb_row_lock_waits和Innodb_row_lock_time_avg加入 Prometheus+Grafana 告警,比盯着 timeout 错误更有预见性
锁超时本质是资源竞争暴露出来的症状,参数只是调节痛感的刻度盘;真正要盯紧的,是哪些 SQL 在抢同一行、哪个服务迟迟不提交、索引是否覆盖了所有高频更新路径。











