温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

为何插入引发死锁

发布时间:2026-09-01 22:14:45 来源:亿速云 阅读:88 作者:小樊 栏目:数据库

“插入引发死锁”通常不是因为 INSERT 本身互斥,而是因为 插入过程中的锁行为 + 并发事务的锁等待顺序不一致 导致的。下面用最常见、最容易踩坑的场景说明。


一、MySQL 中 INSERT 为什么会拿锁?

在 InnoDB 中,INSERT 并不只是“写一行”这么简单,它可能涉及:

  1. 行级锁(隐式锁 / 显式锁)
  2. 唯一索引上的唯一性检查锁
  3. 间隙锁(Gap Lock)
  4. 插入意向锁(Insert Intention Lock)

二、最典型的死锁场景:唯一索引 + 并发插入

表结构

CREATE TABLE t (
  id INT PRIMARY KEY,
  code VARCHAR(20) UNIQUE
);

事务执行顺序

事务 A

BEGIN;
INSERT INTO t(id, code) VALUES (1, 'A'); -- 未提交

事务 B

BEGIN;
INSERT INTO t(id, code) VALUES (2, 'A'); -- 唯一冲突

此时:

  • 事务 B 需要检查 code='A' 是否已存在
  • 发现事务 A 插入了 'A',但未提交
  • 事务 B 等待事务 A 释放锁

事务 A

INSERT INTO t(id, code) VALUES (3, 'B');

如果此时:

  • 事务 A 又去插入某些会被事务 B 锁住的资源
  • 或事务 B 已持有某些锁

互相等待 → 死锁


三、另一个常见原因:间隙锁 + 插入意向锁

CREATE TABLE t (
  id INT PRIMARY KEY,
  age INT,
  INDEX idx_age(age)
);

事务 A

BEGIN;
SELECT * FROM t WHERE age = 20 FOR UPDATE;
-- 加间隙锁,防止别人插入 age=20

事务 B

BEGIN;
INSERT INTO t(id, age) VALUES (10, 20);
-- 需要插入意向锁

➡ 插入被阻塞

事务 A 又插入

INSERT INTO t(id, age) VALUES (11, 20);

➡ 也可能形成死锁


四、为什么“插入”特别容易死锁?

因为:

  • INSERT 不是原子无锁操作
  • 插入时会:
    • 检查唯一索引
    • 加间隙锁
    • 加插入意向锁
  • 多个事务 加锁顺序不同
  • 一旦形成“你等我、我等你”的环 → 死锁

五、如何避免 INSERT 死锁?

✅ 1. 减少事务范围

-- 不要在一个事务里做很多事

✅ 2. 固定插入顺序

-- 所有事务按相同主键顺序插入

✅ 3. 避免 SELECT ... FOR UPDATE + INSERT 混用

✅ 4. 使用 INSERT IGNORE / ON DUPLICATE KEY UPDATE

减少唯一冲突等待

✅ 5. 降低隔离级别(如 RC)

READ COMMITTED

可避免间隙锁(但语义会变)


六、一句话总结

INSERT 引发死锁,本质不是插入本身,而是:
唯一索引检查 + 间隙锁 + 插入意向锁 + 并发事务加锁顺序不同。

如果你愿意,可以把:

  • 数据库类型(MySQL / PG / Oracle)
  • 表结构
  • 死锁日志(show engine innodb status)

发出来,我可以帮你 精准定位是哪一行 SQL 导致的死锁

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI