MySQL 主键索引在 RR 和 RC 隔离级别下的加锁情况总结

SQL herman 90浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xmtxtt,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序

最近群里不少人讨论了一些高质量的问题。我今天抽时间给大家总结一个 MySQL InnoDB 存储引擎各种不同 SQL 情况下,加行锁、间隙锁、next-key lock 做一个总结。如果有错误的地方,请大家指正!

MySQL的所有锁

为了讲清楚相关加锁的情况,我们先来创建一个测试验证用的表。结构如下所示:

CREATE TABLE `xttblog` (
  `id` bigint(20) NOT NULL,
  `name` varchar(16) COLLATE utf8mb4_bin DEFAULT NULL,
  `idcard` bigint(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

然后插入几条测试数据。

insert into `xttblog` values(1,’业余草’,100),(5,'xttblog’,200),
(8,’xttblog’,300),(10,’业余草公众号’,400);

在开始之前,我先来解释一下,RR 和 RC。

RR 隔离级别就是,可重复读。REPEATABLE READ。

RC 隔离级别就是,读已提交。READ COMMITTED。

搞明白 RR 和 RC 后,我们先来看第一种情况。查询条件是聚簇索引,也就是主键索引的精确匹配情况。

// 在id=1的聚簇索引上加X锁
update `xttblog` set name=‘x' where id=1;  
// 在id=1的聚簇索引上加S锁
select * from `xttblog` where id=1 lock in share mode;

上面这种情况下,如果 SQL 是精确查询,不管是 RR 还是 RC 隔离级别下,都会在命中的索引上加 record lock(行锁)。X 锁是排它锁(Exclusive Lock),也有人称作是写锁。S 锁是共享锁(Shared Lock),也有人称作是读锁。不管是 X 锁,还是 S 锁,都是加在行上的。注意,行锁不是加在记录上的,而是加在索引上的!

第二种情况,如果是范围查询,那么在在 RC 隔离级别下,会在所有命中的行的聚簇索引上加 record locks(锁行)。因为 RC 级别下是没有间隙锁的。

// 在id=8和10的聚簇索引上加X锁
update `xttblog` set name='极客时间返现24' where id>7;  
// 在id=1的聚簇索引上加X锁
update `xttblog` set name='极客时间返现24' where id<=1;

第三种情况,在 RR 隔离级别下,会在所有命中的行的聚簇索引上加 next-key locks(锁住行和间隙)。最后命中的索引的后一条记录,也会被加上 next-key lock。

// 在id=8、10(、+∞)的聚簇索引上加X锁
// 在(5,8)(8,10)(10,+∞)加gap lock
update `xttblog` set name=‘x' where id>7;  
// 在id=1、5的聚簇索引上加X锁
// 在(-∞,1)(1,5)加gap lock
update `xttblog` set name=‘x' where id<=1;

第四种情况,如果查询结果为空,即没有命中任何聚族索引,那么,在 RC 隔离级别下,什么也不会锁。

第五种情况,如果查询结果为空,即没有命中任何聚族索引,那么,在 RR 隔离级别下,会锁住查询目标所在的间隙。

// 在(1,5)加gap lock
update `xttblog` set name=‘x' where id=2;

以上,对于主键索引加锁的场景基本上已经全部覆盖到了。如果你还有什么疑问想讨论的,请加我微信:xttblog。

RR 隔离级别实现起来,要比 RC 复杂的多。给你留一个问题,MySQL 是出于什么样的考虑,默认是采用 RR 隔离级别?

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » MySQL 主键索引在 RR 和 RC 隔离级别下的加锁情况总结