锁等待超时是资源争抢暴露的症状,非配置问题;应优先查持锁者及未释放原因,而非调innodb_lock_wait_timeout参数,该参数仅控制等待时长,不解决锁持有不放的根本问题。

锁等待超时不是配置问题,是资源争抢暴露出来的症状
看到 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction,第一反应不该是改 innodb_lock_wait_timeout,而是查谁在持锁、为什么还不释放。这个参数只决定“等多久就放弃”,不解决“别人为什么一直不放锁”。设太小(比如 5 秒),短事务频繁中断;设太大(比如 300 秒),前端早 5 秒就超时了,MySQL 还在傻等,连接池可能先被耗尽。
什么时候可以临时调大 innodb_lock_wait_timeout
仅限明确可控的场景,且必须配合其他动作:
- 批量更新作业:用
SET SESSION innodb_lock_wait_timeout = 600开启连接后立即执行,不要全局设 - 必须同时开启
innodb_rollback_on_timeout = ON,否则超时后事务状态不确定,可能留下半开事务 - 若单次作业真跑超 600 秒,说明逻辑有问题——应拆成
UPDATE ... LIMIT 1000+ 显式COMMIT循环,而不是靠拉长等待硬扛 - 报表类只读查询一般不持锁,不需要调这个值;真正要调的是含写操作的大事务
为什么全局修改 innodb_lock_wait_timeout 常常无效
常见误操作和实际效果:
-
SET GLOBAL innodb_lock_wait_timeout = 30只对新建立的连接生效,已连上的应用连接仍用旧值——线上服务不重启/不重连,等于没改 - 写进
my.cnf的[mysqld]段后,必须mysqladmin reload(部分版本支持)或完整重启 MySQL 才能生效 - JDBC 连接池(如 HikariCP)通常复用连接,即使 MySQL 端 reload 成功,应用侧仍用着旧会话值
- 永远别设成
0:官方明确不推荐,意味着无限等待,极易引发连接堆积
比调参更关键的三件事
真正压降锁等待超时发生率,得盯住源头:
- 查长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - TRX_STARTED) > 60,定位对应应用代码,检查是否有 HTTP 调用、日志写入、sleep 等非数据库操作卡在事务里 - 补缺失索引:
EXPLAIN看 UPDATE/DELETE 是否出现type: ALL,对 WHERE 条件字段建复合索引,避免全表扫描把行锁升级成表级争抢 - 降隔离级别:高并发 OLTP 场景下,
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED能显著减少间隙锁,尤其对范围更新有效
锁等待超时错误本身不可怕,可怕的是把它当普通超时去兜底重试,却放任持锁事务越拖越长。最易被忽略的一点:很多“慢 SQL”根本不是执行慢,而是前面有个事务没提交,它一直在排队等锁——查 INNODB_TRX 比调 innodb_lock_wait_timeout 快十倍。











