MySQL记录锁、间隙锁、临键锁

生成间隙(gap)锁,临键锁(next-key)锁的前提条件是,在rr隔离级别下

  1. 当使用唯一索引来等值查询语句时,如果这行数据存在,不产生间隙锁,而是记录锁
  2. 当使用唯一索引来等值查询语句时,如果这行数据不存在,会产生间隙锁
  3. 当使用使用唯一索引范围查询语句时,对于满足查询条件单不存在的数据产生间隙(gap)锁,如果查询存在的记录就会产生记录锁,加在一起就是临键锁
  4. 当使用普通索引不管是锁住单挑,还是多条记录,都会产生间隙锁
  5. 在没有索引上不管是单挑还是多条记录都会产生表锁

间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;间隙的范围?根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B] 左开右闭。接下来我们开始来验证以上结论 

等值查询且数据存在

事务A 等值查询id=4,因为id是主键,同时是等值查询存在该记录,所以只会在id=4这条记录上加记录锁,不会加间隙锁。

事务B 等值查询id=5,没有锁冲突,所以查询正常,不会堵塞。(如果事务B 等值查询id=4,因为事务A加了记录锁,所以会堵塞)

范围查询示例

事务A 范围查询id>4,那么这里就会存在一个(4,+supernum]的临键(next-key)锁。事务B 插入一条id=6的数据,因为上面存在了(4,+supernum]的临键(next-key)锁,所以会堵塞。如果 事务B 是更新 id=7 的记录,同样会堵塞。

等值查询值示例

事务A 等值查询age=4,因为age是普通索引,所以会产生临键(next-key)锁,范围(1,4]和(4,7](左开右闭原则)。

事务B 插入一个id=6、age=6的数据,因为age值在上面临键锁范围内,所以也会堵塞。

左开右闭原则

通过实践之后,会发现,所谓的左开右闭原则,并不是一定是左开右闭,而是跟主键id有关系。上面的事务A 等值查询age=4,它的当前主键id=4,上一条记录主键id=1,下条记录主键id=7。如果插入 id<1 ,age 在(1,7)范围内,是 左闭右开原则。即age=1能插入,age=7会堵塞。如果插入 1<id<7 ,age 在(1,7)范围内,是 左闭右闭原则。即age=1会堵塞,age=7也会堵塞。如果插入 id>7 ,age 在(1,7)范围内,是 左开右闭原则。即age=1会堵塞,age=7能插入。

无索引示例

等值查询值示例

事务A 等值查询 mobile = 8888884,因为mobile是无索引的,所以这个for update,变成表级排他(X)锁。

事务B 因为事务A已经加了表级的排他锁,所以其它事务无法进行任何的增删改操作。

转载自

MySQL记录锁、间隙锁、临键锁小案例演示 - 知乎 (zhihu.com)

Last modification:November 17, 2023
如果觉得我的文章对你有用,请随意赞赏