题目:什么是死锁?如何避免和解决
难度:low
标签:db/mysql/transaction, mysql/deadlock, difficulty/low
评分:⭐⭐⭐☆(3/5)
说一下什么是死锁。死锁是多个线程对一组资源的竞争,然后大家相互拿到了不同的资源,又互不相互相不能释放,然后大家都在等待其他的线程释放资源,最终导致整个程序的锁死,各个资源都无法进行下一步工作。举个例子,例如一组资源为 1234,这时候线程 A 拿到了资源 1,线程 B 拿到了资源 2,线程 C 拿到了资源 3,这时 A 想要拿资源 2 的时候,发现资源 2 被 B 拿了,A 无法访问,这时候 B 想要拿资源 1 的时候,发现资源被 A 拿了。也无法访问,相互就锁死了。如果大家没有等待的条件,大家都会等到整个线程崩溃。但是如果想要破坏这个死锁,就需要从这几个条件中去排除这个问题。首先是资源的分组性,就是资源的分散性,大家没有一次性拿到全部资源。第二是资源的不可争抢性,就是我拿了资源,我不能抢别人资源。第三,长时间等待没有释放。第四,互斥。这几个性质其实破坏掉了,整个死锁也就不存在了。
解除死锁的话,第一个,如果我要申请一个一组资源,一次申请一组资源,整个资源拿到了我才去执行,这样就不会跟其他人有争抢,也就不会有死锁。第二,如果资源我长时间申请不到,这时候我就放弃当前执行,资源放给其他人,这个事也能继续做。第三,如果我拿到了资源 1,但是我没拿到资源 2,我有强权去把别人的资源 2 拿过来,这时候这个事也能通过。解决死锁的几个这个几个方向。
优点:
不足:
innodb_deadlock_detect=ON(默认),基于 wait-for graph 检测后自动回滚 undo log 少的事务innodb_lock_wait_timeout(默认 50 秒,超时抛 Lock wait timeout exceeded)SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 段、information_schema.innodb_trx、performance_schema.data_lock_waitsINSERT ... ON DUPLICATE KEY UPDATE 引发的死锁补充:
innodb_deadlock_detect=OFF + 依赖 innodb_lock_wait_timeoutSHOW ENGINE INNODB STATUS → 找最近一次死锁 → 看两个事务的 SQL、持有的锁、等待的锁ERROR 1213: Deadlock found when trying to get lock核心考点定位:既要有操作系统层死锁的理论理解,更要掌握 InnoDB 死锁的检测、监控与业务侧规避手段。
知识点拆解:
innodb_deadlock_detect=ON,事务在等锁时会持续构建 wait-for graph,一旦形成环就立刻识别出死锁ERROR 1213,另一事务继续执行innodb_lock_wait_timeout(默认 50 秒),超过直接抛 ERROR 1205: Lock wait timeout exceeded,事务回滚INSERT 或 SELECT FOR UPDATE 请求不同的间隙锁,最终循环等待INSERT ... ON DUPLICATE KEY UPDATE:并发插入相同主键,一个 INSERT 一个 UPDATE 触发死锁UPDATE 无 WHERE 条件:锁全表SHOW ENGINE INNODB STATUS:看 LATEST DETECTED DEADLOCK 段,包含两个事务的 SQL、持有的锁、等待的锁information_schema.innodb_trx:当前运行中的事务information_schema.innodb_locks(5.7)/ performance_schema.data_locks(8.0):当前持有的锁performance_schema.data_lock_waits(8.0):锁等待链,看谁等谁Error 1213 频次监控SELECT ... FOR UPDATE NOWAIT(8.0)就别阻塞version 列 CAS 更新,避免悲观锁冲突innodb_lock_wait_timeout 从 50s 提到 300s,让慢事务有机会完成innodb_deadlock_detect=ON:适合事务短、数量少innodb_deadlock_detect=OFF + 依赖 timeoutinnodb_lock_wait_timeout 减小到 5-10 秒快速失败考察方向:
延伸递进面试题:
innodb_deadlock_detect=OFF 有什么后果?innodb_lock_wait_timeout 让等锁方超时回滚。优点:省 CPU(大事务场景明显);缺点:恢复慢、等待时间长。BEGIN; UPDATE t SET c=c+1 WHERE id=1;(不 commit),会话 2 BEGIN; UPDATE t SET c=c+1 WHERE id=2;,然后会话 1 UPDATE t SET c=c+1 WHERE id=2;,会话 2 UPDATE t SET c=c+1 WHERE id=1;,会话 1 立刻收到 1213 报错。面试官您好,死锁我先从理论上讲清楚,再落到 InnoDB 的具体表现。
理论上死锁有四个必要条件:互斥、占有且等待、不可剥夺、循环等待。破坏任意一个就能防止死锁。经典例子是两个事务,A 拿了资源 1 等 2,B 拿了资源 2 等 1,就形成循环等待,谁都动不了。
但在 MySQL InnoDB 里,死锁的表现和检测方式跟理论不太一样,我主要讲几个点。
InnoDB 的默认行为是自动检测。innodb_deadlock_detect 默认开启,事务在等锁的时候会持续构建 wait-for graph,一旦发现环,就立刻选出牺牲者——通常是 undo log 少、改动少的那个事务,回滚它并抛 ERROR 1213: Deadlock found,另一事务继续执行。所以开发者看到的错误是 1213,业务代码要做重试。检测本身有 O(N²) 开销,事务特别多的场景可以考虑关闭检测,改用 innodb_lock_wait_timeout(默认 50 秒)来兜底——超时会抛 1205 错误。
常见死锁场景有几个。第一是间隙锁交叉,RR 隔离级别下两个事务用不同的 WHERE 条件触发不同间隙锁,最终循环等待。第二是多行更新顺序不同,A 先锁 id=1 再锁 id=2,B 反过来。第三是 INSERT ... ON DUPLICATE KEY UPDATE,并发插相同主键时一个走 INSERT 一个走 UPDATE 触发死锁。第四是 UPDATE 没写 WHERE 条件锁全表。第五是索引缺失导致锁大量行放大冲突面。
排查线上死锁我会按这个链路走:先跑 SHOW ENGINE INNODB STATUS 看 LATEST DETECTED DEADLOCK 段,里面会显示两个事务的 SQL、各自持有的锁、等待的锁;再看 performance_schema.data_lock_waits 找锁等待链;最后看 innodb_trx 找超长事务。慢查询日志里频繁出现 1213 错误就是死锁高发信号。
预防方案我按优先级列一下。第一是固定加锁顺序,所有事务按主键升序加锁,这是最有效的办法,业务侧只要约定统一顺序就能消掉大部分死锁。第二是缩小事务粒度,一条 SQL 能完成就别拆多条,事务内减少锁数量。第三是避免长事务,长事务持有锁越久,越容易和其他事务撞。第四是加索引,无索引的 UPDATE 会锁大量行。第五是用乐观锁绕过,version 列 CAS 更新,冲突就重试,不用悲观锁串行化。第六是8.0 的 NOWAIT / SKIP LOCKED,SELECT FOR UPDATE NOWAIT 拿不到锁立即返回,避免阻塞等待成环。
参数层面,默认配置基本够用,只是长事务多、检测开销大的场景可以 innodb_deadlock_detect=OFF,靠 innodb_lock_wait_timeout 兜底。反过来热点行死锁频发的场景,把 innodb_lock_wait_timeout 调小让失败快一点,业务侧快速重试。
https://chat.deepseek.com/share/wy9ppt0dw6b7uhgyct
题目:什么是死锁?如何避免和解决
难度:low
标签:db/mysql/transaction, mysql/deadlock, difficulty/low
评分:⭐⭐☆☆☆(2/5)
练习次数:2
死锁就是一个彻底解不开的锁,表示这个动作被卡顿停止,没有人工介入是无法解除的。
构成死锁核心有这么几个原因。首先是资源没有一次性申请,不同的线程获取了不同的资源,又相互造成循环等待。
最后我申请资源,你也申请资源,大家申请的,你申请的是我的,我申请的是你的,我不能抢你的,你也不能抢我的,这里边就涉及一个不能抢占其他人资源,也是导致死锁的一个核心原因。
总结一下死锁构成的原因有,没有一次性申请所有资源,相互等待了资源,资源不能强制争抢。这 3 个任意破坏一个都可以解除这个死锁。
优点:
不足:
ERROR 1213、wait-for graph、innodb_deadlock_detect、innodb_lock_wait_timeout)innodb_deadlock_detect=ON 自动检测并回滚 undo log 少的事务,这是"自动解除"的关键SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 段、performance_schema.data_lock_waits、innodb_trxINSERT ... ON DUPLICATE KEY UPDATE补充:
SHOW ENGINE INNODB STATUS 看最近死锁、data_lock_waits 看等待链、innodb_trx 找长事务innodb_deadlock_detect(检测开关)、innodb_lock_wait_timeout(默认 50 秒)ℹ️ 完整讲解见上方首次记录(2026-09-17)