mysql锁等待超时怎么解决_mysql并发异常处理

8次阅读

锁等待超时错误表现为“ERROR 1205 (40001): Lock wait timeout exceeded”,即事务等待锁超时(默认 50 秒),非死锁;可通过 INNODB_TRX 等系统视图定位阻塞源,重点排查 Sleep 状态但未提交事务的连接;避免方法包括:走索引、缩短事务、拆分批量操作、降隔离级别、慎用 FOR UPDATE,而非依赖调高超时参数。

mysql 锁等待超时怎么解决_mysql 并发异常处理

锁等待超时错误长什么样

执行 INSERTUPDATEDELETE 时突然报错:

ERROR 1205 (40001): Deadlock found when trying to get lock; try restarting transaction

或更常见的是:

ERROR 1205 (40001): Lock wait timeout exceeded; try restarting transaction

这说明事务在等某个锁,但等了太久(默认 50 秒),MySQL 主动放弃了。不是死锁,是“干等超时”。

查谁在占着锁不放

先连上 MySQL,用系统视图定位阻塞源头:

SELECT    r.trx_id waiting_trx_id,   r.trx_mysql_thread_id waiting_thread,   r.trx_query waiting_query,   b.trx_id blocking_trx_id,   b.trx_mysql_thread_id blocking_thread,   b.trx_query blocking_query FROM information_schema.INNODB_TRX r INNER JOIN information_schema.INNODB_LOCK_WAITS w ON w.requesting_trx_id = r.trx_id INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id;

如果返回空,说明锁已释放或没发生等待;有结果就看 blocking_query 是什么语句,再查对应线程:

SELECT * FROM information_schema.PROCESSLIST WHERE ID = ;

特别留意状态为 Sleep 却持有事务未提交的连接——这是最常见的“幽灵锁源”。

怎么避免锁等太久

根本思路是缩短锁持有时间 + 减少锁冲突概率:

  • 所有写操作尽量走索引,避免全表扫描导致锁住大量无关行;检查 EXPLAIN 输出,确认 type 不是 ALL
  • 事务里只做必要操作,不要在事务中调外部 API、发邮件、等用户输入
  • 批量更新改用 IN 拆小批次(比如每次 100 行),别一次性 UPDATE …… WHERE id IN (1..10000)
  • 读已提交(READ COMMITTED)比可重复读(REPEATABLE READ)锁范围更小,尤其对非唯一条件查询;可通过 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 临时调整
  • 显式加锁慎用 SELECT …… FOR UPDATE,优先考虑应用层幂等 + 乐观锁(如 UPDATE …… SET version=version+1 WHERE id=? AND version=?

超时参数能调但不能依赖

innodb_lock_wait_timeout 默认 50 秒,可在会话级临时调大:

SET SESSION innodb_lock_wait_timeout = 120;

但这是掩耳盗铃。真正该调的是 wait_timeoutinteractive_timeout(控制空闲连接自动断开时间),防止应用不关连接导致事务长期挂起。生产环境不建议全局调高 innodb_lock_wait_timeout,它掩盖的是设计缺陷,不是 性能瓶颈

并发异常处理的关键不在兜底重试逻辑多漂亮,而在于让锁不出现——或者出现后 1 秒内就释放。很多团队花半天写重试装饰器,却没查过慢查询日志里那条跑了 8 秒的 UPDATE 为什么 没走索引。

星耀云
版权声明:本站原创文章,由 星耀云 2026-01-08发表,共计1604字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。