IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 关于MVCC底层的讨论 -> 正文阅读

[大数据]关于MVCC底层的讨论

MVCC

在本篇内容中主要探讨MVCC中的版本链选取问题。在讨论MVCC底层的版本链前,先复现一个问题。

一、问题复现

1、修改主键id的现象

背景:在MySQL中有一张如下图的表,id是自增主键,name和money是普通的字段,隔离级别是默认的可重复读。
在这里插入图片描述
account表的数据一开始是这样的:
在这里插入图片描述

A、B是两个不同的事务,可以保证的是,他们一开始的快照的一致的。然后分别进行如下顺序操作:

事务A事务B
begin;begin;
select * from account; (1)select * from account; (2)
update account set id = 15 where id = 14;
select * from account; (3)
select * from account; (4)
commit;
select * from account; (5)
update account set id = 16 where id = 15;
select * from account; (6)
commit;
select * from account; (7)

如果现在让你去猜测每次select后的结果,你是否能全部答对呢?

现在揭晓一下答案吧-------------------------------------------------------------

  • (1)、(2)、(4)、(5)的结果是一致的,数据和一开始的快照一模一样。
    在这里插入图片描述

  • (3) 可以看到自己事务B的更改,将id = 14 变更为 id = 15,也没有问题吧。
    在这里插入图片描述

  • 到(6)这块儿就有点奇怪了,先不说select到什么数据,单这个update 能够成功吗,要知道(5) select到的可没有id = 15这条数据。
    答案是 可以执行成功的!!!,这就不得不说起 MVCC 针对的是 select 而提供的 快照读(事务开始前的快照数据),而 update 、insert、delete、select … for update、select lock in share mode 等语句使用的 当前读 (事务最新提交的数据)。
    按照上表的执行顺序,在事务A执行 update 的时候,事务B已经执行过 update 并已提交。所以事务A在 update 的时候是能感知到 id = 15这条数据存在的。
    在这里插入图片描述
    看到这个执行结果是不是又有点疑惑,id = 14已经被事务B给变更到了,为什么事务A依然能select到呢?留着这个疑问继续下去…

  • (7) 的结果是不是好像对,又好像不对,id = 14 没有了,又恢复成你理解的样子了。
    在这里插入图片描述

2、修改普通字段的现象

这里只需要对表里的普通字段按照之前的顺序也改一下(建议数据是唯一的,比较方便看到效果),不会呈现出上述的那些问题,一切都是你理解的样子。

二、解释问题

1、版本链

这里不得不提到 MySQL的 undo log ,了解MVCC的人都知道,它所提供的快照版本是由 undo log 文件提供的。同时 undo log 和 redo log 是有关联的,undo 负责事务的数据回滚,redo 负责事务的数据记录。

同一个事务对同一条数据进行多次修改或者多个事务对同一条数据进行修改,这些修改都会按照时间顺序连成一条链,MVCC可以通过这条链来查找这份数据的历史变更。
对于版本链的每个节点中,会记录着DB_ROW_ID(主键)、DB_TRX_ID(事务ID)、DB_ROLL_PTR(下一历史节点指针)以及对应的数据等。

2、可见性规则

在事务生成快照读的时候,会根据一定的算法来给出对应快照。
该算法会给出三个数据,分别是 活跃事务的数组ID低水位高水位,其中低水位是由数组中的最小值推导的,而高水位由当前最大事务ID + 1生成的。

在这里插入图片描述
如上图所示,分为三块区域:

  • 如果 事务 id 小于低水位,意味着事务在快照生成之前就已经提交了,这些数据都是可见的。

  • 如果 事务 id 是自己本身,也是可见的。

  • 如果 事务 id 在高水位和低水位之间

    • 事务 id 在活跃数组中,则表示生成快照时事务还未提交,数据不可见。
    • 事务 id 不在活跃数组中,则表示在生成快照时事务已提交,数据可见。
  • 如果 事务 id 在高水位中,则表示生成快照时,事务还没有开启,数据当然不可见的。

有了这些可见性原则,我们就可以沿着一条数据的版本链来对比 事务id 和 数据的删除状态来判断是否可见了。

3、解释疑惑

事务A事务B
begin;begin;
select * from account; (1)select * from account; (2)
update account set id = 15 where id = 14;
select * from account; (3)
select * from account; (4)
commit;
select * from account; (5)
update account set id = 16 where id = 15;
select * from account; (6)
commit;
select * from account; (7)

之前提到(6)的时候,数据如下:
在这里插入图片描述
事务B修改 id = 14 为 id = 15 并提交事务后,当事务A再次读取数据时,事务B对 id = 14的修改根据可见性原则(如果事务B后于事务A开启,那么它属于高水位,不可见;如果事务B先于事务A开启,那么它属于活跃事务,也是不可见的)并不可见,所以事务会沿着版本链继续读取之前的事务的变更,符合可见性原则后,呈现出 id = 14这条数据。而 id = 16是由于 update 语句是当前读,并且属于自身操作,是可见的。

而(7)的数据如下:
在这里插入图片描述
(7)已经是在事务A提交后读取的,所以在它读取时,之前事务A和事务B的一切数据都是可见的,所以它只需要根据数据是否处于被删除状态忽略id = 14 ,从而读取到 id = 12 和 id = 16.。

这里有意思的情况是,对主键的 update,相当于删除了一条数据,并且插入了一条新数据!!!

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:49:32  更:2022-05-01 15:49:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:12:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码