Mysql在RR级别当前读如何通过主键索引加锁图文教程

 更新时间:2025年11月14日 08:50:26   作者:usjsjzk  
MySQL在RR隔离级别下,通过主键索引进行当前读时的加锁机制,这篇文章主要介绍了Mysql在RR级别当前读如何通过主键索引加锁的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

RR下select当前读如何让通过主键索引加锁

RC是读已提交,RR是可重复读

下面实验都是在windows mysql8.4.4下进行的

查看当前mysql的隔离级别:select @@transaction_isolation;

下面来探讨一下在RR级别是如何加锁的

建表语句:

create table user (
    id int primary key ,
    name varchar(10),
    age int, 
	salary int);

插入数据:

INSERT INTO user (id, name, age,salary) VALUES
(1, '张三', 20,23),
(2, '李四', 22,24),
(3, '王五', 25,25),
(8, '赵六', 18,26),
(9, '孙七', 30,27);

给 age字段创建二级索引

create index xxx on user(age)

查看当前表的索引

show index from user;

现在一张表中是有主键索引和二级索引的

主键索引加锁方式(RR)

select语句

等值查询

如果当前id在表中记录存在
begin;
select * from user where id = 2 for update;

使用select * from performance_schema.data_locks\G;查询当前锁的情况

可以看到这条语句是给user表加了一个意向排他锁,给 id为3这条数据加了一个纯行锁

如果当前id在表中记录不存在:

把上一个事务提交后执行如下sql

begin;

select * from user where id = 4 for update;

使用select * from performance_schema.data_locks\G;查询当前锁的情况

可以看到已经给开区间为8的这个区间加了间隙锁,即(3,8)这个区间加了间隙锁

再试一下,如果分别查询id小于最小值和最大值是什么情况,存在于表中的间隙,先提交上面事务

如果查询id为0的值(小于当前表中id的最小值):

beginl;
select * from user where id = 0 for update;

查询小于表中小于最小id的id时,会给右边开区间为1的间隙加锁即(负无穷大,1)

如果查询id为999的值(大于当前表中id的最大值):

supremum 表示一个伪记录,用来表示最大索引之后的记录

如果查询的值是大于当前索引值的最大记录,就会给(max(id),正无穷)这个区间加间隙锁

但是查询锁记录的时候,给我们看到的是给这个虚拟记录加了一个临建锁,可以这么认为是存在一个记录,这个记录永远不可以被查询到,就给supremum这条记录上了纯行锁,给(9,supremum)这条记录加了一个间隙锁

查询id为4

begin;
select * from user where id = 4 for update;

使用select * from performance_schema.data_locks\G;查询当前锁的情况

可以看到是给有开区间为8的间隙加了间隙锁,这样也是为了防止有其他事务插入id为4的值出现幻读

范围查询

<=情况

如果范围条件端点在表中

执行如下sql

begin;
select * from user where id <= 3 for update;

使用select * from performance_schema.data_locks\G;查询当前锁的情况

第一行表示的是给表加锁,这里我把它省略了

锁的情况是给id in (1,2,3)的记录都加了临建锁

如果查询条件的端点不在表中

begin;
select * from user where id <= 4 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

图中上锁的信息和端点在表中的相比,多了一个锁住以第一个大于查询条件的端点对应的值的值作为右端的间隙

这里需要多锁一条记录的原因是可能会有其他事务插入id为4的记录,造成幻读

如图:

锁住(3,8)这个间隙,其他事务旧无法在这个间隙插入数据了这样就可以可以防止幻读

当执行一条语句 select * from ... where id <= x for update时,如果x存在于表中会给所有小于等于x的记录加上临建锁,如果不存在于表中,会往后寻找一条数据,锁住x和这条数据对应的间隙

< 情况

如果查询的端点存在于表中

执行如下sql

begin;
select * from user where id < 3 for update;

查询锁的信息

select * from performance_schema.data_locks\G;

图中给所有 id < 3的存在的记录加了临建锁,给开区间右端点为3的间隙加了间隙锁

关于这里为什么明明id是int,在两个元素之间应该不可能插入元素了,为什么还要给这个间隙加锁?

当id为int的时候,确实是不可能往这个间隙插入元素了,但mysql的设计是通用的,如果主键是小数,就会有可能往2到3之前插入 id为2.5的记录,主要是为了设计统一

如果查询的端点不在表中

执行下列sql

begin;
select * from user where id < 4 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

和之前 <= 情况讨论的一样,相比于端点存在表中的情况,多加了一个在表中以比当前查询条件更大的第一条记录作为右端点的开区间加间隙锁,防止出现幻读

当执行 < 这种查询的时候,会给所有小于条件的在表中存在的值加锁,给小于条件的第一条数据和条件之间加上间隙锁

>=情况

如果端点在表中存在

执行如下sql

begin;
select * from user where id >= 3 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

图中给id为3的记录加了纯行锁,给大于 3的id对应的记录加了临建锁

这里有一个现象是 id为3的记录出现了锁退化现象

这里出现锁退化的原因是因为 我们查询 di >= 3的数据,只需要锁住 >=3的这个范围的数据不被修改即可,就没必要对开区间为3的区间加锁了

如果id的范围条件边界不存在:

有下列sql

begin;
select *from user where id >= 4 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

上图中锁的信息是给所有 大于等于4的记录都加上了临建锁

这里可以得出:当执行 >= 的查询是,如果边界条件的值存在的话对应值上的锁会退化为纯行锁,其他记录都加上临建锁,否则所有满足在表中满足条件的记录全部加上临键锁

>的情况

如果端点在表中存在

执行下面sql

begin;
select * from user where id > 8 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

这里会给表中所有大于端点值的记录全部加上临键锁,这里可以把supremum一个虚拟点,对虚拟点加锁就是给大于当前表中索引最大值的间隙加锁

如果查询的端点不存在

执行下面sql

begin;
select * from user where id > 7 for update;

查看锁的信息

select * from performance_schema.data_locks\G;

上面加锁的信息可以看出给表中所有 id > 7 的对应的值加了临键锁

会给表中所有大于id对应的记录加上临键锁

总结

等值查询

  • 如果查询的id不存在(主键),就给第一条大于id对应的记录左侧加间隙锁
  • 如果id存在,就会给对应的id加上纯行锁

范围查询

  • 大于情况:不管id是否存在,都会给表中所有大于id的记录加上临键锁
  • 大于等于情况:
    • id存在:给表中对应的id加上纯行锁,给所有大于id的记录加上临键锁
    • id不存在:给表中所有大于id的记录都加上临键锁
  • 小于情况:
    • id存在:会给所有小于条件的在表中存在的值加锁,给小于条件的第一条数据和条件之间加上间隙锁
    • id不存在:会给第一条小于id对应的记录和后一条数据和加上间隙锁,其他小于等于id的记录都加上临键锁
  • 小于等于情况:
    • id存在:如果x存在于表中会给所有小于等于x的记录加上临键锁
    • id不存在:如果不存在于表中,会往后寻找一条数据,锁住x和这条数据对应的间隙,再给小于等于id的记录加上临键锁

到此这篇关于Mysql在RR级别当前读如何通过主键索引加锁的文章就介绍到这了,更多相关Mysql在RR级别索引加锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 解决MySQL innoDB间隙锁产生的死锁问题

    解决MySQL innoDB间隙锁产生的死锁问题

    线上经常偶发死锁问题,当时处理一张表,也没有联表处理,但是有两个mq入口,并且消息体存在一样的情况,但是是偶发的,又模拟不出来什么场景会导致死锁,只能进行代码分析,问题还原的方式去排查问题,本文给大家介绍了如何解决MySQL innoDB间隙锁产生的死锁问题
    2023-10-10
  • 深入理解sqlserver中的字符编码、排序规则、nvarchar和varchar

    深入理解sqlserver中的字符编码、排序规则、nvarchar和varchar

    本文主要介绍了深入理解sqlserver中的字符编码、排序规则、nvarchar和varchar,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • MySQL的增删查改语句用法示例总结

    MySQL的增删查改语句用法示例总结

    这篇文章主要介绍了MySQL的增删查改语句用法示例总结,是对MySQL学习的基本知识点的一个归纳,需要的朋友可以参考下
    2015-05-05
  • MySQL8.0与MySQL5.7的区别详解

    MySQL8.0与MySQL5.7的区别详解

    MySQL8.0是2018年4月20日发布的全球最受欢迎的开源数据库的一个非常令人兴奋的新版本,下面这篇文章主要给大家介绍了关于MySQL8.0与MySQL5.7区别的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • 十个节省时间的MySQL命令小结

    十个节省时间的MySQL命令小结

    编者在工作中积累起来了一些MySQL命令行客户端技巧,这些技巧或多或少会帮助您节省大量的时间。
    2011-03-03
  • 什么是blob,mysql blob大小配置介绍

    什么是blob,mysql blob大小配置介绍

    BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器。在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型
    2012-02-02
  • MYSQL必知必会读书笔记 第一章(基础)

    MYSQL必知必会读书笔记 第一章(基础)

    数据库(database)是一个以某种有组织的方式存储的数据集合。本文是小编日常收集整理些有关mysql的知识,非常具有参考价值,感兴趣的朋友一起学习吧
    2016-05-05
  • Windows下MySQL详细安装过程及基本使用

    Windows下MySQL详细安装过程及基本使用

    本文详细讲解了Windows下MySQL安装过程及基本使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-12-12
  • MySQL实现字段的自定义排序的方法

    MySQL实现字段的自定义排序的方法

    一般情况下,我们排序都是直接利用 order by 字段 asc/desc;但是如果要排序的字段数据格式并不能直接实现,或者说我们需要指定的顺序且没有什么规律,简单的order by字段就实现不了,所以本文给大家介绍了MySQL实现字段的自定义排序的方法,需要的朋友可以参考下
    2024-04-04
  • 浅谈MySQL 中 null 值的那些坑

    浅谈MySQL 中 null 值的那些坑

    本文解析MySQL中null值的定义与常见问题,如比较运算符失效、WHERE条件误用、IN子查询异常,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-09-09

最新评论