MySQL 锁等待超时问题排查

3次阅读

mysql锁等待超时主因是事务执行过长、未提交或阻塞链路,需查清谁在等、谁在占、为何等不到;通过innodb_trx、innodb_lock_waits等表定位锁关系,结合trx_started、trx_query等字段分析,并排查长事务、缺失索引、异常未回滚、热点行争用等问题。

MySQL 锁等待超时问题排查

MySQL 锁等待超时(Lock wait timeout exceeded)通常不是锁本身的问题,而是事务执行时间过长、未及时提交或存在阻塞链路导致的。核心要查清楚谁在等、谁在占、为什么等不到。

查看当前被阻塞和阻塞者的会话

运行以下 SQL,快速定位锁等待关系:

  • 查询正在等待锁的事务
    select * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT';
  • 查出阻塞者(持有锁且未提交的事务)
    SELECT * FROM information_schema.INNODB_LOCK_WAITS;
    这张表会显示 waiting_trx_id 和 blocking_trx_id 的对应关系。
  • 结合锁信息进一步确认
    SELECT * FROM information_schema.INNODB_LOCKS;
    注意:MySQL 8.0+ 中该表已被移除,改用 performance_schema.data_locks 替代。

分析事务的起始时间与执行语句

INNODB_TRX 表中重点关注:

  • TRX_STARTED:事务启动时间,判断是否异常长时间运行;
  • TRX_QUERY:当前执行的 SQL(可能为 NULL,说明正在等待锁);
  • TRX_MYSQL_THREAD_ID:对应线程 ID,可关联 SHOW PROCESSLIST 查看完整命令和状态;
  • TRX_WAITING_LOCK_ID(MySQL 5.7)或 RESOURCE_ID(8.0+):定位具体被哪把锁卡住。

如果 TRX_QUERY 为空但 TRX_STATE 是 LOCK WAIT,说明事务已执行完语句,正卡在锁上——大概率是上游事务没提交。

检查常见诱因与修复动作

多数锁等待超时背后是开发或运维习惯问题:

  • 长事务未提交:比如应用开启事务后做了大量逻辑处理、调用外部服务、睡眠等,再执行 UPDATE/delete 时发现锁已被占;
    ✅ 解法:缩短事务粒度,只在真正需要一致性操作时开启事务,DML 后尽快 COMMITROLLBACK
  • 缺失索引导致锁范围扩大:UPDATE/DELETE 语句走全表扫描,会升级为表级锁或大量行锁,增加冲突概率;
    ✅ 解法:用 EXPLAIN 确认执行计划,确保 WHERE 条件命中索引。
  • 应用未正确处理异常:代码中捕获异常但忘记 rollback,导致事务一直挂着;
    ✅ 解法:检查事务边界,确保 finally 块或 AOP 切面中兜底 rollback。
  • 并发下热点行争用:如秒杀场景对同一商品库存字段频繁更新;
    ✅ 解法:考虑应用层排队、乐观锁、或拆分行(如按用户哈希分散库存记录)。

临时应急与预防措施

当问题正在发生时:

  • KILL [thread_id] 终止阻塞者(优先 kill 阻塞者,不是等待者);
  • 调整 innodb_lock_wait_timeout(默认 50 秒)仅是掩耳盗铃,不解决根本问题;
  • 开启 innodb_print_all_deadlocks=ON,让死锁日志写入 Error log,辅助分析模式;
  • 定期监控 information_schema.INNODB_TRX 中运行超 10 秒的事务,设置告警。

不复杂但容易忽略。

text=ZqhQzanResources