当前位置: 首页 > news >正文

深入详解MYSQL的MVCC机制

参考资料:

参考视频(注意第二个视频关于幻读的讲解是错误的,详情见本文)

redoLog的结构详解

参考资料


学习内容:

1. MVCC要解决的问题

MVCC要解决的问题是,在不产生脏读等数据库问题的前提下,数据库的查询语句和更改语句不相互阻塞的情况;

在InnoDB中,MVCC仅仅存在于已提交读和可重复读两个隔离级别。

2. MVCC的实现机制

MVCC的实现完全依赖于undolog链表和ReadView两大板块

3. UndoLog链表

(1)InnoDB数据库中的每一行,都有三个隐藏字段

  1. 事务ID(DB_TRX」D):增删改都会默认开启事务,数据行每参与一次事务,就会更新改行的事务ID.
  2. 回滚指针():指向旧版本的数据
  3. Row_ID:  当InnoDB表没有规定主键,并且找不到非空列来构建聚簇索引,那么就会使用Row_ID作为改行的唯一标识,来构建聚簇索引

(2) Undo_Log的结构如下

        数据库中的数据,在参与事务前(修改前),都会记录一个undo_log(包括原先的回滚指针和事务ID)

        然后事务修改数据,并且更新隐藏的事务ID和回滚指针(回滚指针指向undo_log中的上一个版本数据)

        就这样不断地更新,就生成了undo_log版本链表

        其实undo_log版本链的结构要复杂的多,关于undo_log的详细介绍见前面的笔记

(3) 当前读和快照读

  1. 不加锁的select就是快照读(读取MVCC中undo_log的版本链中的数据)
  2. 加锁的select 和增删改等其他语句就是当前读(直接读取数据库表中的数据)

(4)Read view表

① ReadView作用

        当相同的数据被很多事务操作的时候,UndoLog就会变得错综复杂且冗长,那么在进行select快照读的时候,往往很难判断应该读取哪个快照;

        所以在进行select快照读的时候,会生成一个readview,用来帮助确定是需要读取哪个undoLog快照

②ReadView的结构

        ReadView其实是事务ID的集合,其中包括当前正在执行未提交的事务ID列表,创建ReadView的事务ID等

③ ReadView生成时机

        RC(已提交读):ReadView在RC(已提交读)隔离级别下,每进行一次select快照读,就会生成一个ReadView

        RR(可重复读): ReadView在RR(可重复读)隔离级别下,每一个事务只有一个readView,在第一次进行select快照读时生成,后续的快照读,共享这一份readView

④ ReadView的执行逻辑

        当我们进行select快照读时,就会使用ReadView,顺着当前数据以及它所连接的UndoLog版本链,进行事务ID的比对,选出对应的数据版本并返回;

        具体的对比逻辑是:

顺着当前数据以及UndoLog版本链往下找,

  1. 如果事务ID小于readView的事务ID列表中的最小值,表示该数据已提交,那么就进行返回;
  2. 如果事务ID大于readView的事务ID列表中的最大值,该数据不可以返回,继续寻找;
  3. 如果事务ID大于等于readView的事务ID列表中的最小值且小于等于事务ID列表中的最大值:
    1. 如果事务ID在readView的事务ID列表中,且事务ID等于创建readView的事务ID,那么就进行返回,否则不可以返回,继续寻找
    2. 如果事务ID不在readView的事务ID列表中,那么就进行返回;

⑤ InnoDb的MVCC在RR(可重复读)隔离级别下的幻读问题

结论:InnoDB在RR隔离级别下,仅仅解决了部分幻读问题,并没有解决全部

下面将通过举例来说明(数据库在RR隔离级别下)

假设数据库中有原始数据

1)发生幻读的情况

具体步骤如下:

 首先,事务202会进行一次select快照读,并生成ReadView

查询结果为:

然后事务201进行一次数据插入,并提交,此时的数据库为:

然后事务202进行了一次数据更新,这时就会产生UndoLog

最后事务202进行select快照读,因为此时隔离级别为RR(可重复读),所以共用着一份readView

readView会顺着数据和redoLog链进行查询

因为202属于区间[201,202],且202为当前事务ID,

所以查询到的数据为:

此时便发生了幻读

2) 解决幻读的情况

具体步骤如下:

  1. 首先,事务202会进行一次select快照读,并生成ReadView

查询结果为:

b.然后事务201进行一次数据插入,并提交,此时的数据库为:

 然后事务202进行了一次数据更新,这时就会产生UndoLog

  1. 最后事务202进行select快照读,因为此时隔离级别为RR(可重复读),所以共用着一份readView

e.readView会顺着数据和redoLog链进行查询
因为202属于区间[201,202],且202为当前事务ID,201虽然属于这个区间,但是不等于当前事务ID,所以只显示202的数据

所以得到的结果为:

并没有发生幻读



http://www.mrgr.cn/news/98283.html

相关文章:

  • CAP理论 与 BASE理论
  • python——正则表达式
  • C++17模板编程与if constexpr深度解析
  • C# net CMS相关开源软件 技术选型 可行性分析
  • flutter 桌面应用之右键菜单
  • 【Python全栈】应用开发实战案例解析
  • 39.[前端开发-JavaScript高级]Day04-函数增强-argument-额外知识-对象增强
  • 【docker】--部署--安装docker教程
  • 【HD-RK3576-PI】Docker搭建与使用
  • 【第41节】windows的中断与异常及异常处理方式
  • 记录一个虚拟机分配资源的问题
  • 第二十四:查看当前 端口号是否被占用
  • Open-TeleVision源码解析——宇树摇操方案的重要参考:VR控制人形机器人采集数据
  • 高并发内存池(三):PageCache(页缓存)的实现
  • python基础:数据类型转换、运算符(算术运算符、比较运算符、逻辑运算符、三元运算符、位运算符)
  • CTF--bp
  • Kubernetes服务注册到consul流程实践
  • ArkTS语言入门之接口、泛型、空安全、特殊运算符等
  • vulkanscenegraph显示倾斜模型(5.9)-vsg中vulkan资源的编译
  • 基于PySide6与pycatia的CATIA绘图比例智能调节工具开发全解析