MVCC实现原理之ReadView(一步到位)(下)

简介: MVCC实现原理之ReadView(一步到位)

REPEATABLE READ隔离级别下

使用 REPEATABLE READ 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之 后的查询就不会重复生成了。

比如,系统里有两个 事务id 分别为 10 、 20 的事务在执行:

# Transaction 10
BEGIN;
UPDATE student SET name="李四" WHERE id=1;
UPDATE student SET name="王五" WHERE id=1;
# Transaction 20
BEGIN;
# 更新了一些别的表的记录
...

此刻,表student 中 id 为 1 的记录得到的版本链表如下所示:  

d90ac54ccd2c442285876930c0c445f4.png


假设现在有一个使用 REPEATABLE READ 隔离级别的事务开始执行:  

# 使用REPEATABLE READ隔离级别的事务
BEGIN;
# SELECT1:Transaction 10、20未提交
SELECT * FROM student WHERE id = 1; # 得到的列name的值为'张三'

之后,我们把 事务id 为 10 的事务提交一下,就像这样:  

# Transaction 10
BEGIN;
UPDATE student SET name="李四" WHERE id=1;
UPDATE student SET name="王五" WHERE id=1;
COMMIT;

然后再到 事务id 为 20 的事务中更新一下表 student 中 id 为 1 的记录:  

# Transaction 20
BEGIN;
# 更新了一些别的表的记录
...
UPDATE student SET name="钱七" WHERE id=1; 
UPDATE student SET name="宋八" WHERE id=1;

此刻,表student 中 id 为 1 的记录的版本链长这样:  


3a898c326e8b40b188de881e8c6e5750.png

然后再到刚才使用 REPEATABLE READ 隔离级别的事务中继续查找这个 id 为 1 的记录,如下:  

# 使用REPEATABLE READ隔离级别的事务
BEGIN;
# SELECT1:Transaction 10、20均未提交
SELECT * FROM student WHERE id = 1; # 得到的列name的值为'张三'
# SELECT2:Transaction 10提交,Transaction 20未提交
SELECT * FROM student WHERE id = 1; # 得到的列name的值仍为'张三'

5.3 如何解决幻读

接下来说明InnoDB 是如何解决幻读的。

假设现在表 student 中只有一条数据,数据内容中,主键 id=1,隐藏的 trx_id=10,它的 undo log 如下图 所示。

ab09345f19544f26ad7240640daadc36.png


假设现在有事务 A 和事务 B 并发执行, 事务 A 的事务 id 为 20 , 事务 B 的事务 id 为 30 。 步骤1:事务 A 开始第一次查询数据,查询的 SQL 语句如下。  

select * from student where id >= 1;


在开始查询之前,MySQL 会为事务 A 产生一个 ReadView,此时 ReadView 的内容如下: trx_ids= [20,30] , up_limit_id=20 , low_limit_id=31 , creator_trx_id=20 。  


由于此时表 student 中只有一条数据,且符合 where id>=1 条件,因此会查询出来。然后根据 ReadView机制,发现该行数据的trx_id=10,小于事务 A 的 ReadView 里 up_limit_id,这表示这条数据是事务 A 开 启之前,其他事务就已经提交了的数据,因此事务 A 可以读取到。


结论:事务 A 的第一次查询,能读取到一条数据,id=1。


步骤2:接着事务 B(trx_id=30),往表 student 中新插入两条数据,并提交事务。


insert into student(id,name) values(2,'李四');
insert into student(id,name) values(3,'王五');

此时表student 中就有三条数据了,对应的 undo 如下图所示:  

68ba7e43715147818ad0c23e9a5f4c4d.png


步骤3:接着事务 A 开启第二次查询,根据可重复读隔离级别的规则,此时事务 A 并不会再重新生成ReadView。此时表 student 中的 3 条数据都满足 where id>=1 的条件,因此会先查出来。然后根据ReadView 机制,判断每条数据是不是都可以被事务 A 看到。


1)首先 id=1 的这条数据,前面已经说过了,可以被事务 A 看到。


2)然后是 id=2 的数据,它的 trx_id=30,此时事务 A 发现,这个值处于 up_limit_id 和 low_limit_id 之 间,因此还需要再判断 30 是否处于 trx_ids 数组内。由于事务 A 的 trx_ids=[20,30],因此在数组内,这表 示 id=2 的这条数据是与事务 A 在同一时刻启动的其他事务提交的,所以这条数据不能让事务 A 看到。


3)同理,id=3 的这条数据,trx_id 也为 30,因此也不能被事务 A 看见。

5d025af7087b4445b8044177478c0e74.png


结论:最终事务 A 的第二次查询,只能查询出 id=1 的这条数据。这和事务 A 的第一次查询的结果是一样 的,因此没有出现幻读现象,所以说在 MySQL 的可重复读隔离级别下,不存在幻读问题。  


总结


这里介绍了 MVCC 在 READ COMMITTD 、 REPEATABLE READ 这两种隔离级别的事务在执行快照读操作时 访问记录的版本链的过程。这样使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能。


核心点在于 ReadView 的原理, READ COMMITTD 、 REPEATABLE READ 这两个隔离级别的一个很大不同 就是生成ReadView的时机不同:


READ COMMITTD 在每一次进行普通SELECT操作前都会生成一个ReadView


REPEATABLE READ 只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复 使用这个ReadView就好了。


相关文章
|
Java 关系型数据库 中间件
分库分表(3)——ShardingJDBC实践
分库分表(3)——ShardingJDBC实践
1055 0
分库分表(3)——ShardingJDBC实践
|
消息中间件 Kubernetes NoSQL
有状态软件如何在 k8s 上快速扩容甚至自动扩容
有状态软件如何在 k8s 上快速扩容甚至自动扩容
|
缓存 Java Nacos
一文带你理解@RefreshScope注解实现动态刷新原理
一文带你理解@RefreshScope注解实现动态刷新原理
1161 0
一文带你理解@RefreshScope注解实现动态刷新原理
|
6月前
|
人工智能 IDE 程序员
通义灵码打造企业专属 AI 程序员
本文介绍了AI辅助编码领域的产品形态与发展趋势,重点分析了通义灵码的功能与优势。作为一款IDE插件,通义灵码经历了三个发展阶段,从行级代码补全到Multi-Agent全流程支持,覆盖个人开发者与企业用户需求。其核心功能包括代码智能辅助、私域知识融合及自定义扩展机制,有效提升了研发效率。此外,文章还展示了通义灵码在智能化工具链建设中的探索,如代码评审智能体,并通过趣味项目演示了AI程序员的多步骤协作能力。
|
7月前
|
机器学习/深度学习 人工智能 自然语言处理
TsingtaoAI具身智能机器人开发套件及实训方案
该产品套件创新性地融合了先进大模型技术、深度相机与多轴协作机械臂技术,构建了一个功能强大、灵活易用的人机协作解决方案。其核心在于将智能决策、精准感知与高效执行完美结合,为高校实训领域的发展注入新动力。
685 10
|
SQL 存储 监控
(十一)MySQL日志篇之undo-log、redo-log、bin-log.....傻傻分不清!
任何项目都会有日志,MySQL也不例外,而且MySQL更是其中的佼佼者,日志种类繁多,而本篇的目的就是全解MySQL中的各类日志,如撤销日志、错误日志、慢查询日志、中继日志、回滚日志.....
1450 2
|
SQL 自然语言处理 关系型数据库
在 Postgres 中使用 Concat
【8月更文挑战第11天】
989 1
|
监控 NoSQL Redis
Redis Sentinel:秒杀系统背后的可靠性保障神器!
本文详细介绍了如何在个人项目中利用 Redis 哨兵模式保障系统的可靠性与高可用性。哨兵模式通过监控主从服务器状态、自动故障转移和通知客户端等功能,确保在主服务器宕机时系统仍能正常运行。适用于读请求多于写请求的场景,如秒杀系统,能有效缓解数据库压力。同时也探讨了哨兵模式在高并发场景下的优化方法及潜在缺陷,帮助开发者更好地应用该模式。
278 7
Redis Sentinel:秒杀系统背后的可靠性保障神器!
|
存储 关系型数据库 MySQL
MySQL MVCC深度解析:掌握并发控制的艺术
【10月更文挑战第23天】 在数据库领域,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种重要的并发控制机制,它允许多个事务并发执行而不产生冲突。MySQL作为广泛使用的数据库系统,其InnoDB存储引擎就采用了MVCC来处理事务。本文将深入探讨MySQL中的MVCC机制,帮助你在面试中自信应对相关问题。
423 3
|
消息中间件 网络架构
RabbitMQ如何支持动态路由和消息转发
RabbitMQ支持动态路由和消息转发的方式主要是通过Exchange的特性来实现的。
415 0