MySQL间隙锁、Next-Key Lock主要知识点

总体来说,就是MySQL innoDB引擎要在RR隔离级别之下解决幻读的问题,所以引入了间隙锁。

在进行当前读的情况下,对读出的数据的附近的一整个范围(“间隙”)进行加锁,保证满足查询条件的记录不能被插入。

1、幻读与innoDB的隔离级别(为什么会出现间隙锁这个概念)

根据 ISO/ANSI SQL92 所定义的标准,四级隔离级别中,只有在可串行化的级别之下,才可以防止幻读的出现。

隔离级别

所谓幻读,指的是事务A执行过程中,由于事务B并发插入了一条新数据,事务A两次读数据的内容不一样,出现了“虚幻”的新纪录(phantom,幽灵)。

但实际上各厂商的数据库产品并没有严格遵守SQL92标准,比如Oracle只有 RC 和 Serializable 两级隔离级别。

MySQL的innoDB引擎虽然拥有标准的四级隔离级别(其实也是MVCC等手段模拟出来的),不过它有一点显著的不同,就是在 RR 级别下面已经可以防止幻读的发生。

  • 在快照读(snapshot read)的情况下,MySQL通过MVCC(多版本并发控制)来避免幻读。

    快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。主要应用于无需加锁的普通查询(select)操作。

  • 在当前读(current read)的情况下,MySQL通过next-key lock来避免幻读。

    当前读,读取的是记录的最新版本,并且会对当前记录加锁,防止其他事务发修改这条记录。加行共享锁(SELECT ... LOCK IN SHARE MODE )、加行排他锁(SELECT ... FOR UPDATE / INSERT / UPDATE / DELETE)的操作都会用到当前度。行锁可参看 MySQL行锁。

下面主要说明跟间隙锁相关的当前读。

2、innoDB的间隙锁/Next-Key Lock

2-1、明确前提条件
  • innoDB的间隙锁只存在于 RR 隔离级别

所以希望禁用间隙锁,提升系统性能的时候,可以考虑将隔离级别降为 RC。

2-2、间隙锁/Next-Key Lock

间隙锁在innoDB中的唯一作用就是在一定的“间隙”内防止其他事务的插入操作,以此防止幻读的发生:

  • 防止间隙内有新数据被插入。
  • 防止已存在的数据,更新成间隙内的数据。

innoDB支持三种行锁定方式:

  • 行锁(Record Lock):锁直接加在索引记录上面(无索引项时演变成表锁)。

  • 间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别的。

  • Next-Key Lock :行锁和间隙锁组合起来就是 Next-Key Lock。

innoDB默认的隔离级别是可重复读(Repeatable Read),并且会以Next-Key Lock的方式对数据行进行加锁。Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。

当查询的索引含有唯一属性(唯一索引,主键索引)时,Innodb存储引擎会对next-key lock进行优化,将其降为record lock,即仅锁住索引本身,而不是范围。

2-3、何时使用行锁,何时产生间隙锁

对上一节的最后一句做个扩展说明。

  1. 只使用唯一索引查询,并且只锁定一条记录时,innoDB会使用行锁。
  2. 只使用唯一索引查询,但是检索条件是范围检索,或者是唯一检索然而检索结果不存在(试图锁住不存在的数据)时,会产生 Next-Key Lock。
  3. 使用普通索引检索时,不管是何种查询,只要加锁,都会产生间隙锁。
  4. 同时使用唯一索引和普通索引时,由于数据行是优先根据普通索引排序,再根据唯一索引排序,所以也会产生间隙锁。

你可能感兴趣的:(MySQL间隙锁、Next-Key Lock主要知识点)