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

InnoDB存储引擎对MVCC的实现

MVCC

MVCC的目的

在搞清楚MVCC之前,我们要搞懂一个问题,MVCC到底解决的是什么问题?

我用一句话概括,那就是为了解决读-写可以一起的问题!

在我们的印象里,InnoDB可以读读并发,不能读写并发,或者写写并发

这是很正常的想法,因为如果读写并发的化,会有并发问题

而对于写写并发来说,我们还是得加锁,这是没办法改的

但是对于读-写并发来说,我们就可以用MVCC来解决

所以,综上所述,MVCC就是为了解决读-写并发,提高性能.

更准确的说,它是针对读操作的!和写操作关系不大

所以在MVCC的加持上,如果要解决并发问题?
读 + MVCC
写 + 锁

解决哪些并发问题?

先说结论:
对于读已提交

MVCC 解决了脏读

对于可重复读
MVCC 解决了脏读 + 不可重复读 + 幻读


然后其次,我们要搞清楚,有四种隔离级别,我相信大家都知道

读未提交 什么都没解决
读已提交 解决了脏读
可重复读 解决了脏读 + 不可重复读
串行 解决了脏读 +不 可重复读 + 幻读

这我相信你也是滚瓜烂熟

那么对于MVCC来说,它实际解决了哪些问题呢? 这个我们就得分情况了,因为MVCC也是贴合四种隔离级别的!我先说这个就是为了有一个大致的方向

需要注意的是,对于MVCC来说,读未提交 和 串行是束手无策的

你想一想就知道,读未提交连脏读都可以容忍,它还要你MVCC来干嘛,直接读就可以了
对于串行来说,它的读 + 写都是串行化的,不管你读还是写,都要排队,根本没有读 - 写并发的情况

所以,我们需要明确一点,MVCC是针对读已提交 + 可重复读

想清楚这一点,我们再来分别看,MVCC解决的问题,你可能会问,既然你都是贴合四种隔离级别的,那不就是对应隔离级别解决的问题嘛,不是的,这里就是有一个特殊,所以我才会拿来说

对于读已提交

MVCC 解决了脏读

对于可重复读
MVCC 解决了脏读 + 不可重复读 + 幻读

那么比较特殊的一点就是,对于可重复读来说,多解决了一个幻读的问题

综上所述,我们的结论就是,MVCC是针对读已提交 + 可重复读,并且在可重复读的情况下,还多解决了一个幻读问题

如何实现的?

读到这里,你就很好奇了,它是如何实现的呢?

其实很简单,就是一句话,MVCC读的是副本,不是当前的当前正在并发的数据

我们来反过来想,为什么会出现脏读 + 不可重复读,就是因为事务在并发的时候,有可能会修改你正在读的数据,这就导致,读第二次的时候会出现不一致

那我们该如何解决呢?也很简单,就是在事务一开始的时候,保存一份当前数据的副本,这样就算其他事务修改了,它修改的是数据库的数据,而不是我们的副本,这样不就避免了这两个问题吗?

顺着这个思路想,如果每次事务一开始的时候,我们都要取保存一份当前数据的副本,那如果有上亿的读的访问的话,那不是内存炸了?

所以,我们得用MySQL现成的功能来实现这个副本的功能!

所以,自然而然你会想到,Undo log,只有它存着历史的数据,那就是刚刚好的

至此,我们大致就可以引出了三个依赖
第一,隐藏字段
第二,Undo log
第三,Read View

Undo log就不用说了,就是为了生成副本的
Read View 也好说,不过是副本的官方的名字
对于隐藏字段来说,我们就得说一说了

对于聚簇索引来说,他有必要的隐藏列,
trx_id: 事务id
roll_pointer: 指针

事务id,就不用多说了,你需要一个标识来标识事务
对于roll_pointer来说,它和Undo log就会有联系,就是一个指针嘛,我们直接看图就能懂了,为什么需要roll_pointer,还有Undo log实际上长什么样子
在这里插入图片描述
一看就懂,不就是链表嘛,第一个就是最新的记录,后边的都是历史记录

此时,你就大概能明白,为什么需要隐藏字段了把,其实也不是很重要,一笔带过就行

我们特别要注意的是,Read View 副本的结构,这才是我们需要研究的东西
因为我们不熟啊

Read View结构

对于Read View我们先看图,它的大致结构如下

在这里插入图片描述
实际,它记录的不是实际的数据,而是一群活跃的事务id

什么叫活跃的事务id呢?就是那些在并发的时候,在那捣乱的事务,为啥要记录呢?很好理解嘛,在Undo log中,只要有这些捣蛋鬼做的记录,我们就不看,读那些已经提交的记录

结构

creator_trx_id: 创建Readview的事务id
trx_ids: 活跃的事务id列表
up_limit_id: 最小的事务ID
low_limit_id: 下一个最大的事务ID

这里需要特别注意,up_limit_id是最小的
low_limit_id是最大的

还有一点是,这里的最小最大的选取标准是不一样的
这里举个例子,比较容易懂

比如说,事务id列表中,有三个事务id, 1,3,5

我们要假设MySQL只有这三个事务id,其他没有,暗含的意思是,这里的id = 5,是当前生成的最大的事务id

那么up_limit_id 就是1
low_limit_id 是当前生成过的最大的事务id + 1 也就是 5 + 1 = 6

假设事务5提交了,此时的事务列表是1,3
low_limit_id 还是6,因为它类似于Auto_increment 自增id的意思,它会记录当前生成过的最大的事务ID

ReadView的规则

我们研究这个规则,实际上就是研究MVCC的核心规则了

我们得对应着Undo log的版本链来看,版本链就是历史记录

如下
在这里插入图片描述
然后就着
ReadView的结构来看

在这里插入图片描述

事务开始,生成一个ReadView,
然后当前事务,要读取的时候,此时就会去查看两个东西 ReadView + Undo log

查看Undo log就是顺着链表一个一个往下看,找到符合条件的就返回

符合的条件就是规则

第一,如果此时查看的记录trx_id = creator_trx_id,符合条件,读此记录
意思就是,当前记录就是我们自己事务干的事,ReadView是我们当前事务自己生成的,自己读自己的,当然没问题

第二,如果不是自己的,就检查,ReadView的trx_ids,也就是事务id列表
如果发现,当前访问的记录,就是这些捣蛋鬼其中一个干的,那就是不符合条件,如果发现不在这群事务id里边,说明,当前读的是,已经提交了的记录,符合条件

第三,需要注意的是,对于第二,来说,当前的记录的trx_id是介于
up_limit_id < 当前 事务id < low_limit_id,

up_limit_id,和low_limit_id,是一个范围,还有一个功能就是快速的判断

如果,最新的记录是小于up_limit_id的,那么直接就是返回当前记录

为什么呢?因为事务id是单调递增的,和主键id一样,如果我们最新的记录都提交了,那更早的记录是不是都提交了,返回返回没问题!

如果,最新的记录是大于等于low_limit_id的,那么不符合条件,往下找
为什么呢? 因为,如果此时最新的记录是大于low_limit_id的,意思就是这个记录它是在我们事务生成ReadView之后生成的,也就是

我们生成ReadView
然后紧接着,有一个事务进来修改了

那更不可能读这条记录了,比迟到的人还迟到.

综上所述,我们总结一下
trx_id = creator_trx_id,可以读
当trx_id < up_limit_id,可以读
当trx_id >= low_limit_id,不可以读
当up_limit_id <= trx_id < low_limit_id的时候,查看当前记录的id是不是在trx_ids里边,如果在的话,说明这是捣蛋鬼干的,不可以读,如果不存在,可以读

再总结一下,我们只要记住什么时候不可以读

当trx_id >= low_limit_id 的时候,不可以读
当trx_id在范围中间,且当前的记录id,在trx_ids里边,不可以读
其他情况都可以读

读已提交 和 可重复读的不同流程

因为,MVCC要贴合这两个隔离级别解决的问题,所以,他们的流程会有点不一样

对于读已提交来说,事务开始,每一次select都会去获取ReadView
对于可重复读来说,事务开始,到结束,只会获取一次ReadView

这个想想就能明白,读已提交,没有解决不可重复读问题,那么每一次读ReadView的时候,有可能有一些事务就提交了,会读到多的数据

可重复读的时候,由于至始至终,只看一个ReadView,那就是事务开始的时候的ReadView,那可想而知,不会有可重复读的问题,还有幻读的问题了,因为,只看一个ReadView,就算多一万遍,读到的记录还是不会多不会少,所以这也是为什么对于可重复读来说,它可以解决幻读问题了.

总结

所以我们最后来总结一下

MVCC的目的是什么?

为了解决读-写并发,但是只针对读已提交 + 可重复读

MVCC是怎么实现的?

第一,隐藏字段-> 事务id + 指针
第二,Undo log
第三,ReadView

如何实现这个问题,就转换成ReadView如何做校验?

对于读已提交,每次select的时候,获取一个ReadView
对于可重复读,事务开始的时候,获取一个ReadView

做实际的校验

到最后,做校验的问题,就转换成校验的规则是什么?

如果,trx_id >= low_limit_id,不符合条件
如果,up_limit_id <= trx_id < low_limit_id,并且trx_id在trx_ids中,不符合条件
其他情况都符合

相关文章:

InnoDB存储引擎对MVCC的实现

MVCC MVCC的目的 在搞清楚MVCC之前,我们要搞懂一个问题,MVCC到底解决的是什么问题? 我用一句话概括,那就是为了解决读-写可以一起的问题! 在我们的印象里,InnoDB可以读读并发,不能读写并发,或者写写并发 这是很正常的想法,因为如果读写并发的化,会有并发问题 而对于写写…...

【精选】Java项目介绍和界面搭建——拼图小游戏 中

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …...

C++ //练习 10.16 使用lambda编写你自己版本的biggies。

C Primer&#xff08;第5版&#xff09; 练习 10.16 练习 10.16 使用lambda编写你自己版本的biggies。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /*******************************************************************…...

【misc | CTF】BUUCTF 二维码

天命&#xff1a;这题使用到脚本暴力破解压缩包文件里面的密码&#xff0c;还是比较有意思的 一开始是一个二维码&#xff0c;扫码进去有一个假flag 扔进图片隐写工具&#xff0c;啥也没有&#xff0c;都是同一个二维码 使用工具&#xff1a;foremost&#xff0c;直接分离图片&…...

OSCP靶场--Resourced

OSCP靶场–Resourced 考点(1.rpc枚举 2.crackmapexec密码喷洒&#xff0c;hash喷洒 3.ntds.dit system提取域hash 4.基于资源的约束委派攻击rbcd) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC -p- 192.168.188.175 --min-rate 2000 Starting Nmap 7.9…...

Vue路由(黑马程序员)

路由介绍 将资代码/vue-project(路由)/vue-project/src/views/tlias/DeptView.vue拷贝到我们当前EmpView.vue同级&#xff0c;其结构如下&#xff1a; 此时我们希望&#xff0c;实现点击侧边栏的部门管理&#xff0c;显示部门管理的信息&#xff0c;点击员工管理&#xff0c;显…...

【Java程序员面试专栏 算法思维】一 高频面试算法题:排序算法

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊排序算法,包括手撕排序算法,经典的TOPK问题以及区间合并,所以放到一篇Blog中集中练习 题目关键字解题思路时间空间快速排序双指针+递归+基准值分…...

sql注入之sqli-labs-less-1 错误注入

输入?id1 得到登录页面&#xff1a; 通过order by 函数试探&#xff1a; 5的时候报错 试探到3 的时候返回正确的值&#xff1a; 然后继续注入&#xff1a;?id -1 union select 1,2,3 -- 查看回显点&#xff1a; 开始查看数据库内容&#xff1a;id-1 union select 1,databa…...

React withRouter的使用及源码实现

一 基本介绍 作用&#xff1a; 把不是通过路由切换过来的组件中&#xff0c;将react-router 的 history、location、match 三个对象传入props对象上。比如首页&#xff01; 默认情况下必须是经过路由匹配渲染的组件才存在this.props&#xff0c;才拥有路由参数&#xff0c;才能…...

c++之旅——第四弹

大家好啊&#xff0c;这里是c之旅第三弹&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦&#xff01; 本篇文章的主…...

Mysql整理-主从复制

MySQL的主从复制是一种常见的数据复制和分布式数据共享方法。在这种架构中,一个MySQL服务器充当主(master)服务器,而一个或多个其他MySQL服务器充当从(slave)服务器。数据从主服务器复制到从服务器,实现数据的分布和备份。这种设置主要用于数据备份、读取扩展、灾难恢复…...

100个百万阅读公众号爆文案例

100个100万公众号爆文案例 自从公众号流量推送修改之后&#xff0c;原来的私域玩法一去不复返&#xff0c;公域公众号正在崛起 现在公众号的玩法就是找爆款&#xff0c;去对标&#xff0c;去学习&#xff0c;努力使自己的公众号进入流量池&#xff0c;然后吃流量主的收益 这里…...

UnityAPI的学习——Transform类

Transform类继承自Component类&#xff0c;并实现了IEnumberable接口。Transform是GameObject必须拥有得一个组件&#xff0c;用来管理所在GameObject对象的坐标位置、选择角度、和大小缩放。 Transform实现了IEnumberable接口&#xff0c;因此可以在程序中使用foreach()方法快…...

(全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF

研究生英语读写教程基础级教师用书PDF 研究生英语读写教程提高级教师用书PDF pdf下载&#xff08;完整版下载&#xff09; &#xff08;1&#xff09;研究生英语读写教程基础级教师用书PDF &#xff08;2&#xff09;研究生英语读写教程基提高级教师用书PDF...

GO基本类型

Go语言同时提供了有符号和无符号的整数类型。 有符号整型&#xff1a;int、int8、int64、int32、int64无符号整型&#xff1a;uint、uint8、uint64、uint32、uint64、uintptr 有符号整型范围&#xff1a;-2^(n-1) 到 2^(n-1)-1 无符号整型范围: 0 到 2^n-1 实际开发中由于编…...

怎么快速编辑视频

背景&#xff1a;怎么简单快速编辑视频 利用FFmpeg功能&#xff0c;简单快速编辑视频&#xff0c;如按9:16提前剪切视频、替换背景音乐。 下载FFmpeg&#xff1a;https://ffmpeg.org/download.html 将FFmpeg的路径添加到环境变量中&#xff1a; Windows&#xff1a;在系统的环…...

基于vue-office实现docx、xlsx、pdf文件的在线预览

概述 在做项目的时候会遇到docx、xlsx、pdf等文件的在线预览需求&#xff0c;实现此需求可以有多种解决方式&#xff0c;本文基于vue-office实现纯前端的文件预览。 效果 如下图&#xff0c;分别为docx、xlsx、pdf三种类型的文件在线加载后的效果。你也可以访问官方预览网址…...

数据库系统架构与DBMS功能探微:现代信息时代数据管理的关键

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…...

51单片机-(中断系统)

51单片机-&#xff08;中断系统&#xff09; 了解51单片机中断系统、中断源、中断响应条件和优先级等&#xff0c;通过外部中断0实现按键控制LED亮灭为例理解中断工作原理和编程实现过程。 1.中断系统结构 89C51/52的中断系统有5个中断源 &#xff0c;2个优先级&#xff0c;…...

c++之旅——第三弹

大家好啊&#xff0c;这里是c之旅第三弹&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦&#xff01; 一.命名空间;…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...