当前位置:网站首页>MVCC是什么
MVCC是什么
2022-08-04 23:36:00 【大佬,菜菜,带带】
什么是MVCC
MVCC是一种同一主键的行记录保存多个版本的机制,实现在并发读-写情况下不加锁读,同时解决了脏读、不可重复读。
MVCC如何实现
MVCC通过版本链实现。
什么是版本链
版本链就是一个链表,每个节点上保存的是行记录的一个版本,其中头节点是行记录的最新版本,头节点后的第一个节点是行记录最新版本的上一个版本,头节点后的第二个节点是行记录最新版本的上上一个版本,以此类推。
版本链如何实现
版本链又是如何实现的呢?其实InnoDB的行记录中除了我们自定义的列之外,还有三个隐藏列,分别是trx_id,roll_pointer,row_id:
trx_id:事务id,表示这条行记录是哪个事务生成/修改的
roll_pointer:指向undo log中这条行记录的上一个版本
row_id:当用户没有指定主键且没有非null的唯一列时,使用
row_id作为主键
通过roll_pointer就形成了版本链,有了版本链就可以查询到行记录的每个版本。
如何解决脏读、不可重复读问题
假如是我们来解决脏读和不可重复读问题,在有版本链的情况下应该如何解决呢?(一条行记录,创建/修改它的事务已经提交了,下面将简称已提交行记录,反之为未提交行记录)
脏读是指读到了未提交行记录,我们很容易想到:版本链上那么多版本,我们读一条已提交行记录不就行了?
不可重复读是指在一个事务中两次读取一个行记录,但是获取到的数据不一致,原因是在两次读取的间隔中有其他事务修改了这个行记录并提交了,那如果在当前事务提交之前无论读多少次都读取版本链上的同一个
已提交行记录,这样的话读到的数据不就一样了?那么哪个版本才能让我们在当前事务提交之前的各个时期都能读取到呢?那就是当前事务开始时的已提交行记录。至于当前事务开始时的未提交行记录甚至是当前事务开始之后才生成的未提交/已提交行记录都是不行的。
提炼一下解决脏读和不可重复读需要的条件:
解决脏读是需要读一个
已提交行记录;解决不可重复读是需要读取
当前事务开始之前的已提交行记录。
也就是说我们只要读取当前事务开始时的已提交行记录,并且当前事务没有提交之前每次都读同一个版本,那就可以解决脏读和不可重复读问题。
非礼勿视——ReadView
大概的思路就是这样,但是我们怎么知道我们读取的行记录是不是在当前事务开始时就已经提交了呢?这时候就轮到行记录隐藏字段trx_id上场了。
可能大家会想到,喔!我懂了!直接判断行记录的事务id和当前事务id的大小就行了,小于当前事务id的就是在当前事务开始时就已经提交的行记录;大于当前事务id的就是在当前事务开始之后才提交的行记录。
需要注意的是,事务id是事务对行记录创建/修改时分配的,而不是事务提交的时候分配的。一个事务的事务id小,但是因为操作比较多,可能比其他事务id大的事务提交的时间还要晚。所以只凭行记录事务id和当前事务id是无法判断生成这条行记录的事务是否是在当前事务之前提交的。
那么到底是如何实现判断的呢?InnoDB设计了一个ReadView,这个ReadView很简单,就4个部分,分别是:
m_ids:当前事务生成ReadView时活跃事务的列表(简称活跃列表)min_trx_id:活跃列表中最小的事务id(最小事务id)max_trx_id:生成ReadView时下一个要分配的事务id(最大事务id)creator_trx_id:生成ReadView的事务id(当前事务id)
有了ReadView我们就可以知道我们读取的这个行记录是不是在当前事务开始时就已经提交了:
首先这个版本的行记录事务id一定不能大于或者等于最大事务id,如果不满足,说明生成这个行记录的事务是在当前事务开始之后才生成的,肯定不行。
如果这个版本的行记录事务id比最小事务id要小,说明在当前事务生成时它已经提交了,可以读。
如果这个版本的行记录事务id和当前事务id一样,说明这个记录是当前事务修改/生成的,可以读。
如果这个版本的事务id比最小事务id要大,但是又比最大事务id要小,那就难办了,我们得看它是否在活跃事务列表中:
如果在,那说明这个行记录在当前事务开始时还没有提交,不行;
如果不在,那说明这个行记录在当前事务开始时提交了,可以读。
为什么需要活跃列表:一些事务的事务id比最小事务id要大,但是它可能在当前事务开始之前就已经提交了。
边栏推荐
- [QNX Hypervisor 2.2用户手册]10.6 vdev mc146818
- 三大技巧让你成功入门3D建模,零基础小白必看
- MySQL的安装与卸载
- Pytest learning - fixtures
- Since a new byte of 20K came out, I have seen what the ceiling is
- 基于Appian低代码平台开发一个SpaceX网站
- 未来我们还需要浏览器吗?(feat. 枫言枫语)
- 线性DP(下)
- 怎么将自己新文章自动推送给自己的粉丝(巨简单,学不会来打我)
- node中package解析、npm 命令行npm详解,node中的common模块化,npm、nrm两种方式查看源和切换镜像
猜你喜欢

Implementing class target method exception using proxy object execution

MySQL基础篇【子查询】

「津津乐道播客」#397 厂长来了:怎样用科技给法律赋能?

OpenCV:10特征检测
![[Cultivation of internal skills of memory operation functions] memcpy + memmove + memcmp + memset (4)](/img/08/e115e1b0d801fcebef440ad4932610.png)
[Cultivation of internal skills of memory operation functions] memcpy + memmove + memcmp + memset (4)

uniapp sharing function - share to friends group chat circle of friends effect (sorting)

KT148A语音芯片怎么烧录语音进入芯片里面通过串口和电脑端的工具

为何越来越多人选择进入软件测试行业?深度剖析软件测试的优势...

没有这些「伪需求」,产品经理的 KPI 怎么完成?

4-《PyTorch深度学习实践》-反向传播
随机推荐
功耗控制之DVFS介绍
如何写好测试用例
生产者消费者问题
Pytest学习-Fixture
当panic或者die被执行时,或者发生未定义指令时,如何被回调到
年薪50W+的测试工程师都在用这个:Jmeter 脚本开发之——扩展函数
C5750X7R2E105K230KA(电容器)MSP430F5249IRGCR微控制器资料
小黑leetcode冲浪:94. 二叉树的中序遍历
一点点读懂regulator(二)
C语言实现扫雷 附带源代码
小黑leetcode之旅:95. 至少有 K 个重复字符的最长子串
没有这些「伪需求」,产品经理的 KPI 怎么完成?
应用联合、体系化推进。集团型化工企业数字化转型路径
407. 接雨水 II
KT148A语音芯片怎么烧录语音进入芯片里面通过串口和电脑端的工具
话题 | 雾计算和边缘计算有什么区别?
对写作的一些感悟
建模师经验分享:模型学习方法
Uniapp dynamic sliding navigation effect demo (finishing)
学会反射后,我被录取了(干货)