暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

三种锁机制

杂食笔记 2022-08-28
548

Record lock,Gap Lock ,next-key Lock三种锁机制:

首先,还是假设我们有表t:

sn_id (primary  key)ID(unique 索引)age (普通索引)num(非索引)
55024123
1010030456
1515024789


下面举的所有例子都是以这个表t为基础。

好了,现在让我们来介绍这个三种锁:

其实这三种锁的形式,用这张图就大概可以表明了:

record Lock:又称为记录锁,是针对索引记录(index record)的锁定,是简单的一种锁形式。一般都是命中索引后,对该索引加锁。如:

select * from t where sn_id=5 for update;
select * from t where age=24 and num=123 for update;(这个在某些场景下会升级成gap lock)

就是记录锁。

Gap Lock锁定的是索引记录之间的间隙、第一个索引之前的间隙或者最后一个索引之后的间隙,如上面表记录存在的间隙就有(-∞,5),(5,10),(10,15),(15,+∞)。

这里有两点需要注意下

1.间隙表只有在可重复读的隔离级别或者更高的级别才会有,并且参数innodb_locks_unsafe_for_binlog为ON

2.间隙表主要的目的是解决幻读。

Next-key Lock:既会锁表记录的间隙,也会锁住表记录,相当于上面record Lock+Gap Lock

1.检索条件为主键

1)命中主键

SELECT * FROM t WHERE sn_id =5 FOR UPDATE;

这时是record锁,锁住了sn_id=5,这条记录。因为命中了唯一的条件,不会有幻读的情况发生。

2)命中某个范围

例如:事务A执行了下面的sql:

SELECT * FROM t WHERE sn_id BETWEEN 5 and 10 FOR UPDATE;

那事务B想要执行这个sql,就会报错:

insert into t values (8,8,8);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

因为在执行事务A时,已经将(5,10】这整个区间都锁住了,因此想要向这个区间插入数据,会报等锁时间超长的错。(PS:这里的5到10是一个左闭右开区间,因为在RR的隔离条件下,范围匹配时,会锁住遍历范围的最后一条索引记录,即sn_id=10

3)未命中

如事务A执行了下面的sql:

SELECT * FROM t WHERE sn_id=6  FOR UPDATE;

这时由于没有命中索引,其锁住的范围为sn_id=6左右范围的索引,即(5,10)这个区间,这样就会防止有新的sn_id=6插入,从而造成幻读。

2.检索条件为唯一索引:

1)命中索引

SELECT * FROM t WHERE ID =50 FOR UPDATE;

这时是不存在gap锁的,而只是record锁,因为命中了唯一的条件,不会有幻读的情况发生。

2)‍命中某个范围

SELECT * FROM t WHERE ID >50 and ID<100 FOR UPDATE;

这里在表中记录遍历的范围为ID∈(50,100)

针对二级索引ID(50,100】这个范围内都会被lock起来,(范围匹配时,会锁住遍历范围的最后一条索引记录,所以ID=100会被锁住)。

针对聚簇索引,则不会进行加锁。

如果语句是

SELECT * FROM t WHERE ID >=50 and ID<100 FOR UPDATE;

二级索引ID【50,100】这个范围内都会被lock起来,同时聚簇索引sn_id= 5 也会被锁住。

3)未命中

SELECT * FROM t WHERE ID =60 FOR UPDATE;

这里在表中记录遍历的范围为 ID∈(50,100)

二级索引ID (50,100)这个范围内都会锁起来,由于这个是精确匹配,不会在最后的遍历值上加锁。聚簇索引上也不会有锁。

3.非唯一索引:

1)命中索引

假设事务A执行下面的sql

SELECT * FROM t WHERE age =24 FOR UPDATE;

这时候由于是非唯一的索引,为防止出现幻读的情况,不光会在age=24这个索引上加锁,还会在(-∞,24)(24,30)这个间隙中加锁。同时,age =24的索引ID和sn_id都会加上锁。

2)命中某个范围

SELECT * FROM t WHERE age >20 and age< 25 FOR UPDATE;

这里在表中记录遍历的范围为 age∈(-∞,24】(24,30)

那锁住的范围其实就是(-∞,24】,(24,30],由于是范围检索,会锁住遍历范围的最后一条索引记录。

3)未命中

SELECT * FROM t WHERE age =25 FOR UPDATE;

这时锁住的范围其实就是 age∈(24,30),

如果没有where条件没有命中任何索引,则全表会被锁。

4.最后的小结:

1)唯一索引精确等值检索,Next-Key Lock就退化为record lock,不会加gap lock

范围检索,会锁住where条件中相应的范围,范围中的记录以及间隙,换言之就是加上record lockgap lock

2)非唯一索引精确等值检索,Next-Key Lock 会对间隙加gap锁,以及对应检索到的record lock。

范围检索,会锁住where条件中相应的范围,范围中的记录以及间隙,换言之就是加上record lock和gap lock。

3)非索引检索,全表间隙加gap lock,全表记录加record lock

文章转载自杂食笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论