什么是死锁_mysql死锁产生原因

14次阅读

死锁是多个事务因争夺资源而互相等待无法推进的状态;InnoDB自动检测并回滚代价最小事务,核心原因是加锁顺序不一致与循环等待,需同时满足互斥、持有并请求、不可剥夺、循环等待四条件。

什么是死锁_mysql死锁产生原因

死锁是指两个或多个事务在执行过程中,因争夺资源而互相等待,导致所有相关事务都无法继续推进的状态。mysql(特别是 InnoDB 引擎)中一旦发生死锁,系统会自动检测并强制回滚其中一个事务(通常选择代价最小的那个),抛出错误:Error 1213 (40001): Deadlock found when trying to get lock

死锁产生的核心原因

本质是“加锁顺序不一致 + 循环等待”。InnoDB 死锁必须同时满足四个条件:互斥、持有并请求、不可剥夺、循环等待。实际开发中最常见、最可控的诱因有以下几类:

  • 锁获取顺序不同:事务 A 先更新行 1 再更新行 2,事务 B 却先更新行 2 再更新行 1。双方各自持有一把锁,又申请对方的锁,形成闭环。
  • 索引路径引发隐式锁竞争:比如对非唯一普通索引字段执行 UPDATE ... WHERE name = 'xxx',InnoDB 会先锁 name 索引项,再通过回表锁主键。若另一事务已持有该主键行的 X 锁,并反向尝试锁 name 索引,就可能死锁。
  • 间隙锁(gap lock)或 next-key 锁参与竞争:范围查询(如 WHERE age BETWEEN 20 AND 30)会锁定索引间隙。多个事务对重叠间隙加锁,且顺序错乱时,容易触发死锁,尤其在可重复读(RR)隔离级别下更常见。
  • 长事务 + 高并发:事务运行时间越长,持有锁的时间就越久,与其他事务发生交叉加锁的概率呈指数上升;配合高并发写入,死锁频率显著提高。

哪些操作不会导致 MySQL 死锁?

明确一点:表级锁(如 MyISAM 使用的锁)本身不支持事务,也没有死锁检测机制,所以不会产生死锁。而 InnoDB 的行级锁机制天然具备死锁可能性——这也正是它支持高并发事务的代价之一。

一个典型复现场景

假设有用户表 users(id, name, balance),其中 name 有普通索引:

  • 事务 A 执行:UPDATE users SET balance = balance + 100 WHERE name = 'Alice';
  • 事务 B 同时执行:UPDATE users SET balance = balance - 50 WHERE id = 1001;
  • 如果事务 A 已拿到 name='Alice' 索引锁,正准备回表锁主键 id=1001;而事务 B 已持有 id=1001 的 X 锁,又试图加 name 索引上的锁(例如执行了 select ... for UPDATEname 条件),此时就会触发死锁。
text=ZqhQzanResources