「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。
当使用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,称为“间隙(gap)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙(Next-Key)锁。
准备表格
我们在 SQL 操作中演示一下 MySQL 的间隙锁。
打开两个终端,终端 1 将执行删除操作,终端 2 将执行插入操作。
首先创建一张表:
create teble gap(id tinyint primary key, val int);
然后插入一些数据:
insert into gap values(2,2), (3,3), (17,17);
区间导致的间隙锁
接下来开始演示间隙锁,使用终端 1 开启一个事务,执行删除 id
大于 2 小于 7 的记录的操作,不要提交,代码为:
begin;
delete from gap where id > 2 and id < 7;
使用终端 2 插入一条 id
为 5 的数据,代码为:
insert into gap values(5, 5);
此时,终端 1 的事务会得到一个锁定了范围 的间隙锁,当我们对 id
落在这一范围的记录进行插入和更新操作时,这一操作就会被阻塞。如下图所示,上方终端为终端 2 ,下方终端为终端 1。
只有当终端 1 的事务提交或回滚之后,终端 2 的操作才能执行。如下图所示,终端 1 事务回滚后,终端 2 操作执行。由于之前终端 2 的操作被阻塞,因此执行耗时很长(40.63秒)。
不存在的键导致的间隙锁
如果在执行更新和删除操作时,对不存在的键进行操作,此时也会导致间隙锁的出现。
我们在执行了之前的操作后,表 gap
的数据如下:
使用终端 1 开启一个事务,执行删除 id
为 10 的记录的操作,不要提交,代码为:
begin;
delete from gap where id = 10;
此时,表中并没有 id
为 10 的记录。于是,终端 1 的事务会得到一个锁定了范围 的间隙锁。当终端 2 试图插入 id
落在这一区间的记录时,操作就会被阻塞,如上图所示。
如果终端 2 试图插入 id
为 5 或 17 的记录,则不受锁的影响,如下图所示: