page contents

什么是间隙(Next-Key)锁?

轩辕小不懂 发布于 2022-03-17 15:36
阅读 545
收藏 0
分类:数据库
3317
Nen
Nen
- 程序员

当使用范围条件而不是相等条件检索数据的时候,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,称为“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙(Next-Key)锁。间隙锁是InnoDB中行锁的一种,但是这种锁锁住的不止一行数据,它锁住的是多行,是一个数据范围。间隙锁的主要作用是为了防止出现幻读(Phantom Read),用在Repeated-Read(简称RR)隔离级别下。在Read-Commited(简称RC)下,一般没有间隙锁(有外键情况下例外,此处不考虑)。间隙锁还用于恢复和复制。

间隙锁的出现主要集中在同一个事务中先DELETE后INSERT的情况下,当通过一个条件删除一条记录的时候,如果条件在数据库中已经存在,那么这个时候产生的是普通行锁,即锁住这个记录,然后删除,最后释放锁。如果这条记录不存在,那么问题就来了,数据库会扫描索引,发现这个记录不存在,这个时候的DELETE语句获取到的就是一个间隙锁,然后数据库会向左扫描,扫到第一个比给定参数小的值,向右扫描,扫描到第一个比给定参数大的值,然后以此为界,构建一个区间,锁住整个区间内的数据,一个特别容易出现死锁的间隙锁诞生了。

在MySQL的InnoDB存储引擎中,如果更新操作是针对一个区间的,那么它会锁住这个区间内所有的记录,例如UPDATE XXX WHERE ID BETWEEN A AND B,那么它会锁住A到B之间所有记录,注意是所有记录,甚至如果这个记录并不存在也会被锁住,在这个时候,如果另外一个连接需要插入一条记录到A与B之间,那么它就必须等到上一个事务结束。典型的例子就是使用AUTO_INCREMENT ID,由于这个ID是一直往上分配的,因此,当两个事务都INSERT时,会得到两个不同的ID,但是这两条记录还没有被提交,因此,也就不存在,如果这个时候有一个事务进行范围操作,而且恰好要锁住不存在的ID,就是触发间隙锁问题。所以,MySQL中尽量不要使用区间更新。InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,那么InnoDB也会使用间隙锁!

间隙锁也存在副作用,它会把锁定范围扩大,有时候也会带来麻烦。如果要关闭,那么一是将会话隔离级别改到RC下,或者开启innodb_locks_unsafe_for_binlog(默认是OFF)。间隙锁只会出现在辅助索引上,唯一索引和主键索引是没有间隙锁。间隙锁(无论是S还是X)只会阻塞INSERT操作。

在MySQL数据库参数中,控制间隙锁的参数是innodb_locks_unsafe_for_binlog,这个参数的默认值是OFF,也就是启用间隙锁,它是一个布尔值,当值为TRUE时,表示DISABLE间隙锁。

请先 登录 后评论