MySQL行锁加锁规则

概述:

行级锁加锁规则比较复杂,不同场景加锁形式不同,对记录加锁时,加锁的基本单位是next-key lock(左开右闭),其在不同的场景下会退化成间隙锁或者记录锁。通过以下实验来看看不同的场景具体是什么锁。
行级类型主要有三类:

Record Lock:记录锁,只在一条记录上机上锁;
Gap Lock:间隙锁,锁定某一个范围,不包含记录本身,左开右开;
Next-Key Lock:记录锁和间隙锁的组合,包含记录本身,左开右闭;
普通的select语句不会对记录加锁,需要加锁使用下面两种方式:

select ... lock in share mode;	//共享锁
select ... for update;	//独占锁

实验准备:

创建表:

create table user(
  id INT AUTO_INCREMENT,
  name VARCHAR(23) NOT NULL,
  age INT,
  primary key(id)
  )engine = INNODB default CHARSET = utf8;

插入一些数据:
在这里插入图片描述

唯一索引等值查询

会话1执行:查询一条存在的记录
begin;
select * from user where id = 7 for update;

执行以下语句查看加锁情况:

select * from performance_schema.data_locks\G;

在这里插入图片描述
我们重点关注第二行,第一行是因为插入了行级锁所以会生成一个表级别的意向锁。
上面红框是锁的属性主要信息

  • LOCK_TYPE:锁类型(RECORD:记录锁)
  • LOCK_MODE:X(独占锁),REC_NOT_GAP(记录锁,只锁一行)
  • LOCK_DATA:锁的值(主键索引id值为7的一条记录)

因此当查询条件是唯一索引等值查询且记录时存在的,只会锁住要查询的记录一条。

会话1执行:查询一条不存在的记录
begin;
select * from user where id = 8 for update;

在这里插入图片描述

  • LOCK_TYPE:锁类型(RECORD:记录锁)
  • LOCK_MODE:X(独占锁),GAP(间隙锁)
  • LOCK_DATA:锁的值(主键索引id值为11)
    因为是间隙锁,所以主键索引id的加锁范围是(7,11);

唯一索引范围查找

select * from user_2 where id >= 7 and id <10 for update;

在这里插入图片描述
由上图看出在id=7上加了一条记录锁。另外还有范围(7, 11)的间隙锁,所以加锁的范围是[7, 11)。

非唯一索引等值查询

首先给字段age加上索引;

查找的非唯一索引记录存在
select * from user_2 where age = 26 for update;

在这里插入图片描述
在这里插入图片描述

  • 首先给非唯一索引age_index加上next-key lock,范围(25, 26];
  • 使用非唯一索引,记录存在。还会加上间隙锁,规则是向下遍历一个区间,间隙锁范围(26,28)
    根据以上两点,使用普通索引且记录存在,会加上两个锁,分别是next-key lock(25, 26]和间隙锁(26,28)。
非唯一索引且值不存在
select * from user_2 where age = 23 for update;

在这里插入图片描述
非唯一索引不存在时,会在查找的值所在的区间加上间隙锁(20,25);

非唯一索引范围查找

select * from user_2 where age >= 20 and age < 24 for update;

在这里插入图片描述

在这里插入图片描述

  • 开始找的是age = 20,会加上next-key lock(18, 20],因为使用的不是唯一索引,索引不会退化为记录锁。
  • 由于是范围查找,向后一个区间走,到age = 25,加上next-key lock(20, 25],使用普通索引不会退化为间隙锁。
    综上所述,会产生两个next-key lock (18, 20] 和 (20, 25].

总结

行锁加锁的基本单位是next-key lock,只是会在不同的场景会退化为记录锁或者间隙锁

唯一索引等值查询
  • 记录存在,next-key lock退化为记录锁
  • 记录不存在,next-key lock退化为间隙锁
非唯一索引等值查询
  • 记录存在,除了next-key lock锁外,还会向后一个区间加上间隙锁,一共两把锁;
  • 记录不存在,只会加上next-key lock锁,再退化为间隙锁,只有一把锁;
范围查找
  • 唯一索引范围查找,如果查找的条件存在,则会有一条记录锁,然后会给后面的范围加上next-key lock(某些条件下会退化为间隙锁);
  • 非唯一索引范围查找,next-key lock 不会退化为记录锁或者间隙锁

另外,锁是在遍历索引的时候加上的,并不是针对输出结果加锁。因此当在线上执行update、delete、select…for update等有加锁性质的语句,需要判断语句是否走索引,如果是全表扫描的话,会对每一个索引加next-key lock,等于把整个表锁住了。

就是这事,散会。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值