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

来源:这里教程网 时间:2026-02-28 20:38:28 作者:

锁等待超时错误长什么样

执行

INSERT
UPDATE
DELETE
时突然报错:
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 = <blocking_thread>;
特别留意状态为
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_timeout
interactive_timeout
(控制空闲连接自动断开时间),防止应用不关连接导致事务长期挂起。生产环境不建议全局调高
innodb_lock_wait_timeout
,它掩盖的是设计缺陷,不是性能瓶颈。

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

UPDATE
为什么没走索引。

相关推荐