next-key 锁

lllllan ... 2022-4-16 数据库 About 2 min

# next-key 锁

next-key 锁包含两部分:

  • 行锁(锁住记录)
  • 间隙锁(锁住记录之间的间隙)

假设有如下的表和数据。

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(0,0,0), (5,5,5), (10,10,10), (15,15,15), (20,20,20), (25,25,25);
1
2
3
4
5
6
7
8
9

为了解决幻读的问题,InnoDB引入了间隙锁,就是锁住两个值之间的间隙:

img

这样,当你执行 select * from t where d = 5 for update 的时候,就不止是给数据库中已有的6个记录加上了行锁,还同时加了7个间隙锁。这样就确保了无法再插入新的记录,从而解决了幻读。

间隙锁和行锁合称【next-key lock】,每个 next-key lock 是 前开后闭区间 。也就是说,我们的表t初始化以后,如果用 select * from t for update 要把整个表所有记录锁起来,就形成了7个next-key lock,分别是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +suprenum]。

InnoDB给每个索引加了一个不存在的最大值suprenum,这样才符合我们前面说的“都是前开后闭区间”

锁冲突

现在你知道了,数据行是可以加上锁的实体,数据行之间的间隙,也是可以加上锁的实体。但是间隙锁跟我们之前碰到过的锁都不太一样。

比如行锁,分成读锁和写锁。下图就是这两种类型行锁的冲突关系。

img


但是间隙锁不一样,**跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。**间隙锁之间都不存在冲突关系。

img

这里session B并不会被堵住。因为表t里并没有c=7这个记录,因此session A加的是间隙锁(5,10)。而session B也是在这个间隙加的间隙锁。它们有共同的目标,即:保护这个间隙,不允许插入值。但,它们之间是不冲突的。

# 间隙锁加锁机制

看了几篇博客,甚至不能统一,看不太懂,不知道哪个准确,就先放着

Last update: 2022年4月16日 09:31
Contributors: lllllan