浅谈mysql mvcc

目录

前言

mvcc 是如何工作的?

数据的更新


前言

mvcc 与一个事物的隔离级别有关,未提交读永远读的是当前值,串行化是通过加锁实现,这两种隔离级别都与mvcc 没有任何关系。只要一提到mvcc应该想到的是读提交以及可重复读,大家有没有想过都是mvcc,为啥这两个隔离级别所呈现的结果有些不一样呢?难道会有两套mvcc 吗?当然不是,对于这个问题,稍后我会说明的。

我先举一个简单的例子。下面是一个表的初始化语句。

CREATE TABLE `t` (`id` int(11) NOT NULL,`k` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB;
insert into t(id, k) values(1,1),(2,2);
sessionAsessionBsessionA

在此我说明下,sessionA 是在同一个事物下,事务的隔离级别是可重复读,sessionB 是另外一个事物。是不是感觉很神奇,sessionB 对数据操作成功了,sessionA 没有收到任何干扰。

是不是感觉sessionA 在begin 的时候像相机一样为数据表拍了一张快照。而这个快照也是我们常说的一致性读视图即 consistent read view。它的作用是事务执行期间用来定义“我能看到什么数据”。

mvcc 是如何工作的?

在上面我们讲到了快照,大家是不是感觉我在扯淡,100G的库,你也去快照,你要拷贝100G的数据,别人不会拍死你,放心好了拍不死我的。

其实在启动一个事物的时候,并不需要拷贝数据,只需要在事物系统申请一个事物id 叫做 transaction id,这个id 是原子递增的,意味着一个数据库不会出现两个相同的事物id

每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id 赋值给这个数据版本的事务 ID,记为 row trx_id。同时,旧的数据版本要保留在undo log 里,并且在新的数据版本中,能够有信息可以直接拿到它。

可以这么说,数据表中的一行记录,其实可能有多个版本,每个版本都有自己的row trx_id。

按照可重复读的定义,一个事物启动的时候,能够看到所有已经提交的事物结果。但是之后其他事物的更新,它却看不见。

它是怎么找到自己能够看见的数据呢,会拿到每个版本的 row trx_id,如果是在我启动以后生成的row trx_id,继续往前找,直到找到自己提交的或者是本事物启动之前提交的。

为了方便比较,在实现上,innodb 为每个事物构建一个数组,用来保存这个事物启动瞬间,当前正在“活跃” 的所有事物ID。“活跃” 指的是,启动了还没有提交的。

数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。

这个视图数组和高水位,就组成了当前事物的一致性视图。

而数据版本的可见性规则,就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的。

就拿一致性视图而言,规则是这样的:

  1. 如果 row trx_id 小于这个视图数组的最小值,说明已经提交了,那么这个数据就是可见的。

  2. 如果 row trx_id 大于这个高水位,肯定不可见呀,说明事物还没有创建

  3. 如果 row trx_id 在 最小值和高水位之间又有两种情况:row trx_id刚好就在视图数组是说明还没有提交也不可见,不在视图数组里说明提交了就可见。

所以你现在知道了,InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

所以一个数据版本,对于一个事务视图来说,除了自己更新总是可见以外,有三种情况:

  1. 版本未提交,不可见;

  2. 版本已提交,但是是在视图创建后提交的,不可见;

  3. 版本已提交,而且是在视图创建前提交的,可见。

下面我在在回到最开始提到的那个问题,读提交为啥又有些不一样呢,让我们在回顾一下什么是读提交,在事务中,我们可以读到已经提交的事物,只要在我事物中的任何一个时刻提交的,我都可以读到。上面的规则对于读提交同样适用,只不过读提交是在每个select语句都会去申请一个transaction id作为它的row trx_id,同时也会构建一个新的事物数组。

数据的更新

上面我们讲到了mvcc,其实只是在select 用到,如果是update ,或者下面的语句。

select k from t where id=1 lock in share mode;
​
select k from t where id=1 for update;

大家都知道更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。

或者是select 语句加上了 share mode 共享锁 或者 for update 拍他锁,这些都只能用到当前读,与mvcc 没有一点关系了。

所以这些语句执行后,会对行进行加锁,update 加行锁,share mode 加的是读锁, for update 加的是写锁。读到最新的数据

而这些锁都是两阶段锁,从加锁开始到事物结束。这么做对于数据库来说也是无赖之举,为了保证数据的一致性,是数据的同步技术。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/712057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue+element ui上传图片到七牛云服务器

本来打算做一个全部都是前端完成的资源上传到七牛云的demo,但是需要获取token,经历了九九八十一难,最终还是选择放弃,token从后端获取(springboot)。如果你们有前端直接能解决的麻烦记得私我哦!…

『Linux从入门到精通』第 ㉒ 期 - 动静态库

文章目录 💐专栏导读💐文章导读🐧什么是库?🐧为什么要有库?🐧写一个自己的库🐦方法一🐦方法二 静态库🐦标准化🐦方法三 动态库🐦配置动…

python中自定义报错

class MyError(Exception):def __init__(self,num):#录入的数Exception.__init__(self)self.numnumdef __str__(self):return 这是我定义的第%d个异常 %(self.num)使用 try:raise MyError(4) except MyError as e:print(e)raise 其作用是指定抛出的异常名称,以及异常…

题目 1240: 生日日数

题目描述: CCC老师的生日是YY年MM月DD日,他想知道自己出生后第一万天纪念日的日期(出生日算第0天)。 代码: package lanqiao;import java.time.LocalDate; import java.util.*;public class Main {public static void main(String[] args)…

数据结构题目①——数组

前言 本篇文章为博主进行代码随想录——数组练习后的总结会涉及到每一道题目的详细的思路整理,以及本人的易错点,希望对大家有所帮助 数组介绍: 数组在C语言中就已经有所涉及,它是一个最基础的数据结构,而在数据结构中…

Java学习—FileInputStream

在Java编程中,文件操作是日常任务之一。无论是读取配置文件、处理图像,还是读写日志文件,理解如何有效地进行文件读取都是非常重要的。Java提供了多种方式来操作文件,而FileInputStream是其中最基础也是最直接的一种。本文将深入探…

Spring面试系列-01

1. 什么是 Spring 框架? Spring中文翻译过来是春天的意思,被称为J2EE的春天,是一个开源的轻量级的Java开发框架, 具有控制反转(IoC)和面向切面(AOP)两大核心。Java Spring框架通过声明式方式灵活地进行事务的管理,提高开发效率和质量。 Spring框架不仅限于服务器端的…

three 层级模型

group.remove(mesh1,mesh2);Vector3与模型位置、缩放属性 Group层级模型(树结构) 创建了两个网格模型mesh1、mesh2,通过THREE.Group类创建一个组对象group,然后通过add方法把网格模型mesh1、mesh2作为设置为组对象group的子对象,然后在通过执行scene.a…

jenkins部署maven项目

流程: jenkins从代码仓库读取代码,将代码文件放入jenkins的工作空间,将jenkins工作空间的代码进行打包,将jar包远程发送给服务器。 一:所需插件二:Tools 三:System: 配置ssh连接的…

github要求2fa身份验证

前言 github登陆的时候发现要求2fa验证, 2fa是啥?咋验证? 解决 2FA(Two-Factor Authentication,双因素身份验证) 就是在账户和密码的基础上增加一次验证码验证,这样即使密码被窃取,由于黑客没有你的验证码也无法登陆 就像是银行的u盾一样…

python63-Python的循环之循环使用else

Python的循环都可以定义else代码块&#xff0c;当循环条件为False 时&#xff0c;程序会执行else代码块。如下代码示范了为while循环定义else代码块。 # !/usr/bin/env python# -*- coding: utf-8 -*-# Time : 2024/01# Author : Laopicount_i 0while count_i < 5:print(c…

Java集合相关面试题(2024大厂高频面试题系列)

1、说一说Java提供的常见集合&#xff1f;&#xff08;画一下集合结构图&#xff09; 在java中提供了量大类的集合框架&#xff0c;主要分为两类&#xff1a; 第一个是Collection 属于单列集合&#xff0c;第二个是Map 属于双列集合 在Collection中有两个子接口List和Set。…

【力扣hot100】刷题笔记Day14

前言 又是新的一周&#xff0c;快乐的周一&#xff0c;快乐地刷题&#xff0c;今天把链表搞完再干活&#xff01; 114. 二叉树展开为链表 - 力扣&#xff08;LeetCode&#xff09; 前序遍历 class Solution:def flatten(self, root: Optional[TreeNode]) -> None:if not r…

回溯 Leetcode 51 N皇后

N皇后 Leetcode 51 学习记录自代码随想录 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所…

Linux —— 链接文件

硬链接 一般情况下&#xff0c;文件名和inode号码是"一一对应"关系&#xff0c;每个inode号码对应一个文件名。但是&#xff0c;Unix/Linux系统允许&#xff0c;多个文件名指向同一个inode号码。 这意味着&#xff0c;可以用不同的文件名访问同样的内容&#xff1b;对…

软件开发常见模型解析

软件开发常见模型解析 摘要&#xff1a;本文将为您详细介绍软件开发过程中常见的几种模型&#xff0c;包括瀑布模型、敏捷开发模型、螺旋模型、迭代模型和原型模型。通过了解这些模型的原理、优缺点&#xff0c;帮助您在不同的软件项目中选择最适合的开发模型。 一、引言 在…

【IC前端虚拟项目】inst_buffer子模块DS与RTL编码

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 需要说明一下的是,在我所提供的文档体系里,并没有模块的DS文档哈,因为实际项目里我也不怎么写DS毕竟不是每个公司都和HISI一样对文档要求这么严格的。不过作为一个培训的虚拟项目,还是建议在时间充裕…

Docker技术概论(3):Docker 中的基本概念

Docker技术概论&#xff08;3&#xff09; Docker 中的基本概念 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

基于java+springboot女士电商平台系统源码+文档设计

基于javaspringboot女士电商平台系统源码文档设计 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源…

C语言----动态内存管理(2)

1.这里总结动态内存管理里面的错误 &#xff08;1&#xff09;使用malloc开辟空间以后直接赋值 这个就是malloc开辟失败返回空指针&#xff0c;直接给空指针赋值就是错误的&#xff0c; tip1:使用malloc开辟空间以后一定要判断是否为空 &#xff08;2&#xff09; 越界访问…