MySQL的间隙锁问题

MySQL的间隙锁【Next-Key锁】

什么是间隙锁

间隙锁是一个在索引记录之间的间隙上的锁

其中间隙锁的使用就是为了保证某一个间隙内的数据在锁定情况下不发生任何的变化,例如MySQL的默认隔离级别为可重复读(RR),则其使用间隙锁的目的即是为了防止幻读

MySQL中的间隙锁场景

我们假设有下面的场景:id作为主键,number字段上有一个非唯一索引的二级索引,那么此时哪些场景不能再插入number = 5的记录??

MySQL的间隙锁问题_第1张图片

答:只有我们保证number之前,number = 5现有记录之间,以及number之后不能插入新的记录,则新的number = 5的记录就不能插入进来!!

那么MySQL底层是怎么做到的,即使用到了我们的间隙锁!!!

MySQL的间隙锁问题_第2张图片

此时我们锁住了(4,5),(5,5),(5,11)之间的间隙,则number = 5的记录就无法在插入进去了。。。

间隙锁锁定的区域

我们根据检索条件(number = 5)向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。
在上面的场景中,检索条件where number = 5的话,那么间隙锁的区间范围为(4,11),也就是我上面在右侧画出来的几部分之和。

间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:

  • (1)防止间隙内有新数据被插入
  • (2)防止已存在的数据,更新成间隙内的数据(例如防止numer=4的记录通过update变成number=5)

InnoDB使用间隙锁的条件

(1)必须在RR级别
(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)

场景判断

对于上面的案例,我们观察一下几个案例,来熟悉一下间隙锁的使用:

案例1:

session 1:
start  transaction ;
select  * from news where number = 4 for update ;

session 2:
start  transaction ;
insert into news value(2,4);#(阻塞)
insert into news value(2,2);#(阻塞)
insert into news value(4,4);#(阻塞)
insert into news value(4,5);#(阻塞)
insert into news value(7,5);#(执行成功)
insert into news value(9,5);#(执行成功)
insert into news value(11,5);#(执行成功)

MySQL的间隙锁问题_第3张图片

此时我们查询的是number = 4的条件,此时它会锁定区域【2,4】以及【4,5】,所以此时前三条对于该间隙中的记录的插入操作均阻塞,必须等到select for update事务提交以后才会执行,而后面的几条不在该间隙锁的间隙范围内的操作均可以成功。

案例2:

session 1:
start  transaction;
select * from news where number>4 for update;

session 2:
start  transaction;
update news set id=2 where number=4 ;#(执行成功)
update news set id=4 where number=4 ;#(阻塞)
update news set id=5 where number=5 ;#(阻塞)
insert into news value(2,3);#(执行成功)
insert into news value(null,13);#(阻塞)

MySQL的间隙锁问题_第4张图片

此时检索条件为范围查询:number > 4,故我们选择向左找到了最靠近4的值作为左区间,向右取无穷大作为右值,即我们的索引的范围【4,无穷大】

那么对于事务2来说:当我们的number在此间隙区间内的,就会阻塞住,防止插入新的记录导致幻读的发生。

总结

  • next-key(间隙锁)其实包含了记录锁和间隙锁,即锁定了一个范围,并且索引记录本身,InnoDB默认加锁方式为next-key锁
  • 对于主键索引或者是唯一索引,因为其都具有唯一性,故我们不可能重复插入相同的索引对应的记录,则我们对其只会索引当前行,即行锁,不会使用间隙锁。
  • MVCC(多版本并发控制)解决的是不可重复读的问题,间隙锁解决的是幻读问题。

故我们不可能重复插入相同的索引对应的记录,则我们对其只会索引当前行,即行锁,不会使用间隙锁。

  • MVCC(多版本并发控制)解决的是不可重复读的问题,间隙锁解决的是幻读问题。

你可能感兴趣的:(数据库,mysql,数据库)