MySQL锁机制

文章详细阐述了MySQLInnoDB存储引擎的三种锁机制:RecordLock、GapLock和Next-KeyLock,以及它们在不同事务隔离级别下的应用。重点讨论了Next-KeyLock的左开右闭区间和在RepeatableReads隔离级别中的作用,同时提到了两种优化情况,即唯一索引等值查询时锁的退化。此外,文章还分析了加锁规则和示例,展示了如何影响并发操作。
摘要由CSDN通过智能技术生成

前置知识补充:

左闭右闭代表的就是[left,right]的区间,也就是left=0,right= numsSize-1 左闭右开代表的就是[left,right)的区间,也就是left=0,right= numsSize 左开右闭代表的就是(left,right]的区间,也就是left=-1,right= numsSize-1

lock in share mode (共享锁) 和 for update((排他锁)事务控制

[select ... lock in share mode]

在符合条件的rows上都加了共享锁,这样的话,其他事务可以读取这些记录,但是无法修改这些记录,直到你这个加锁的事务提交或回滚【否则直接锁等待超时】

[select ... for update]

在符合条件的rows上都加了排他锁,其他事务也就无法读取和修改这些记录,直到你这个加锁的事务提交或回滚【否则直接锁等待超时】

在MySQL数据库中,为了解决并发问题,引入了很多的锁机制,很多时候,数据库的锁是在有数据库操作的过程中自动添加的。

问题:你知道MySQL InnoDB的锁,到底锁的是什么吗?(完整阅读完笔记再来回答)

Record Lock

Record Lock,翻译成记录锁,是加在索引记录上的锁。例如,select c1 from t where c1=10 for update

;会对c1=10这条记录加锁,为了防止任何其他事务插入,更新或删除c1值为10的行。

需要特别注意的是,记录锁锁定的是索引记录。即使表没有定义索引,InnoDB也会创建一个隐藏的聚簇索引(row_id),并使用这个索引来锁定记录。

Gap Lock

Gap Lock ,翻译成间隙锁,他指的是在索引记录之间的间隙上的锁,或者在第一个索引记录之前或最后一个索引记录之后的间隙上的锁。

那么,这里所谓的Gap(间隙)又怎么理解呢?

Gap指的是InnoDB的索引结构中可以插入新值的位置。

当你用语句 select...for update 锁定一组行时。InnoDB可以创建锁,应用于索引中的实际值以及他们之间的间隙。例如,如果选择所有大于10的值进行更新,间隙锁将阻止另一个事务插入大于10的新值。

既然是锁,那么就可能会影响到数据库的并发性,所以,间隙锁只有在Repeatable Reads这种隔离级别中才会起作用。

在Repeatable Reads这种隔离下,对于锁定的读操作(select ... for update、lock in share mode

、update操作、delete操作时,会进行如下的加锁:

  • 对于具有唯一搜索条件的唯一索引,InnoDB只锁定找到的索引记录,而不会锁定间隙。

  • 对于其他搜索条件,InnoDB锁定扫描的索引范围,使用gap lock或next-key lock来阻塞其他事务插入范围范围覆盖的间隙。

也就是说,对于select ... for update 、lock in share mode、update和delete等语句处理时,除了对唯一索引的唯一搜索外都会获取gap锁或next-key锁,即锁住其扫描的范围。

Next-Key Lock

Next-Key锁是索引记录上的记录锁和索引记录之前间隙上的间隙锁的组合。

假设一个索引值包含值10、11、13和20。此索引可能的next-key锁包括以下区间:

(- ∞ ,10】、(10 ,11】、(11 ,13】、(13,20】、(20 , ∞】

对于最后一个间隙, ∞不是一个真正的索引记录,因此,实际上,这个next-key锁只锁定最大索引值之后的间隙。

所以,Next-Key的锁的范围都是左开右闭的。

Next-Key Lock和Gap Lock一样,只有在InnoDB的RR隔离级别中才会生效。

MySQL的加锁原则

前面介绍了Record Lock、Gap Lock和Next-Key Lock,但是并没有说明加锁规则。关于加锁规则,我是看了丁奇大佬的《MySQL实战45讲》中的文章之后理解的,他总结的加锁规则里面,包含了两个“原则”、两个“优化”和一个“bug”:

原则1:加锁的基本单位是 next-key lock。是一个前开后闭区间。

原则2:查询过程中访问到的对象才会加锁。

优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key 退化为间隙锁

bug1:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

假如,数据库表中当前有如下记录:

主键索引:0,5,10,15,20,25

当我们执行 update t set d = d + 1 where id = 7 的时候,由于表 t 中没有 id = 7 的记录,所以:

  • 根据原则1,加锁单位是 next-key lock,session A 加锁范围就是(5,10】;

  • 根据优化2,这是一个等值查询( id = 7 ),而 id = 10 不满足查询条件,next-key lock退化成间隙锁,因此最终加锁的范围是(5,10)

当我们执行 select * from t where id >= 10 and id < 11 for update 的时候

  • 根据原则1,加锁单位是 next-key lock,session A 加锁范围就是 (5,10】,范围查找就往后继续找,找到 id = 15 这一行停下来

  • 根据优化1,主键id上的等值条件,退化为行锁,只加了 id = 10 这一行的行锁。

  • 根据原则2,访问到的都要加锁,因此需要加 next-key lock(10,15】。因此最终加的是行锁 id = 10 和 next-key lock (10,15】。

当我们执行 select * from t where id > 10 and id <=15 for update 的时候

  • 根据原则1,加锁单位是 next-key lock,会给(10,15】加上 next-key lock,并且 因为id 是唯一键,所以循环判断到 id = 15 这一行就应该停止了。但是,InnoDB 会往前扫描到第一个不满足条件的行为止,也就是 id = 20。而且由于这是个范围扫描,因此索引 id 上的(15,20】这个 next-key lock 也会被锁上。

假如,数据库表中当前有以下记录:

普通索引:0,5,10,15,20,25

当我们执行 select id from t where c = 5 lock in share mode 的时候:

  • 根据原则1,加锁单位是 next-key lock,因此会给(0,5】加上next-key lock。要注意 c 是普通索引,因此仅访问 c = 5 这一条记录是不能马上停下来的,需要向右遍历,查到 c = 10 才放弃。

  • 根据原则2,访问到的都要加锁,因此要给(5,10】加 next-key lock。

  • 根据优化2:等值判断,向右遍历,最后一个值不满足 c=5 这个等值条件,因此退化成间隙锁(5,10)。

  • 根据原则2,只有访问到的对象才会加锁,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁。

当我们执行 select * from t where c >= 10 and c < 11 for update 的时候:

  • 根据原则1,加锁单位是 next-key lock,会给(5,10】加上 next-key lock,范围查找就往后继续找,找到 id=15 这一行停下来

  • 根据原则2,访问到的都要加锁,因此需要加 next-key lock (10,15】。

  • 由于索引 c 是非唯一索引,没有优化规则,也就是说不会蜕变成行锁,因此最终 session A 加的锁是 索引 c 上的 (5,10】和(10,15】这两个 next-key lock。

总结

以上,我们介绍了 InnoDB 中的锁机制,一共有三种锁,分别是 Record Lock、Gap Lock和Next-Key Lock。

Record Lock 表示记录锁,锁的是索引记录。Gap Lock是间隙锁,说的是索引记录之间的间隙,包含第一个索引之前以及最后一个索引之后的间隙。Next-Key Lock是Record Lock和GapLock的组合,同时锁索引记录和间隙。他的范围是左开右闭的。

在 InnoDB 的 RR 事务隔离界别下,加锁的基本单位是 next-key lock,只要扫描到的数据都会加锁,唯一索引上的范围查询会访问到不满足条件的第一个值为止。

同时,为了提升性能和并发度,也有两个优化点:

  • 索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

  • 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值