select...for update,表锁?行锁?间隙锁?( 二 )


select...for update,表锁?行锁?间隙锁?

文章插图
图片
这里锁住的是 age 字段的 [18, 28) 这区间 。
结论:查询条件为普通索引,且有值,间隙锁
2.6 普通索引(空值)说明:普通索引,数据不存在 。
执行悲观锁查询:
select * from user where age = 19 for update;执行插入操作,被锁住了:
insert into user values(3, 14, '楼仔小弟', 20);ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
select...for update,表锁?行锁?间隙锁?

文章插图
图片
这里锁住的是 age 字段的 (18, 28) 这区间 。
结论:查询条件为普通索引,且空值,间隙锁
2.7 索引(范围查询)说明:这里的索引,包括主键索引、唯一索引和普通索引 。
执行悲观锁查询:
select * from user where id > 1 for update;【select...for update,表锁?行锁?间隙锁?】执行插入操作,被锁住了:
insert into user values(3, 14, '楼仔小弟', 20);ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
select...for update,表锁?行锁?间隙锁?

文章插图
图片
这里其实可以对 id = 1 的数据进行更新,对于其它数据,都被锁?。?锁住的范围是 id 字段的 (1, 4],(4, 8],(8, 正无穷) 区间 。
结论:查询条件为索引 , 且是范围查询,间隙锁 。
2.8 无索引执行悲观锁查询:
select * from user where user_name = "楼仔" for update;执行插入操作,被锁住了:
insert into user values(3, 14, '楼仔小弟', 20);ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
select...for update,表锁?行锁?间隙锁?

文章插图
这里明显是锁表了,但是为什么锁的信息还是行锁呢,知道的同学 , 可以私我哈~~
结论:查询条件为无索引,表锁 。
03 加锁规则3.1 规律总结我们把上面的结论进行汇总:
select...for update,表锁?行锁?间隙锁?

文章插图
图片
总结如下规律:
  1. 当查询条件为主键和唯一索引,当有值时 , 是行锁;
  2. 当查询条件为主键和唯一索引,当为空值时 , 是间隙锁;
  3. 当查询条件为普通索引,是间隙锁;
  4. 当查询条件为索引,且为范围查询,是间隙锁;
  5. 当查询条件无索引,是表锁 。
3.2 加锁规则那是否有一套加锁规则呢?
为了便于大家理解,我先普及 3 个概念:
  • Record Lock:行锁
  • Gap Lock:间隙锁 , 锁定一个范围,但不包含记录本身
  • Next-Key Lock:行锁 + 间隙锁 , 左开右闭,比如(1,5]
其实 MySQL 大佬林晓斌在极客时间讲过 , 后来也有很多博主转发过他的加锁规则,我直接把这套规则贴一下 。
两个“原则”:
  • 原则 1:加锁的基本单位是 next-key lock , 其中 next-key lock 是前开后闭区间;
  • 原则 2:查找过程中访问到的对象才会加锁 。
两个“优化”:
  • 优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁;
  • 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁 。
3.3 分析一下这里我们结合上面的案例,来解读这套加锁规则 。
针对我们前面总结的 5 条规律,我们先分析这两条:
  • 当查询条件为主键和唯一索引,当有值时 , 是行锁;
  • 当查询条件为主键和唯一索引,当为空值时 , 是间隙锁 。
下面我们根据 “两个原则” + “两个优化” 来分析一下 。
根据 “原则 1”,加锁的基本单位是 next-key lock,当 “索引上为等值查询” 时(即能查到该数据) , 根据 “优化 1”,间隙锁退化为行锁 。


推荐阅读