数据库 MVCC 详解

news2024/9/23 23:33:48

目录

1. 什么是 MVCC?

2. MVCC 的好处?

3. 快照读?当前读分别是什么?怎么理解?

3.1 快照读

3.2 当前读

4. 数据库的四种隔离级别

5.  MVCC 实现原理

5.1 隐藏字段

5.2 undo log(版本链)

5.3 readView

6. readView 深层详解

7. MVCC中是如何解决不可重复读的?

8. 间隙锁解决幻读问题(补充点)


1. 什么是 MVCC?

MVCC 英文全称叫 "Multiversion Concurrency Control",翻译过来就是 "多版本并发控制"。在 MySQL 众多存储引擎中只有 InnoDB 中实现了 MVCC 机制。

2. MVCC 的好处?

首先我们要清楚,在 InnoDB 存储引擎下,假设事务A我们对一行数据进行修改操作,是会对这一行数据进行加写锁的;如果此时事务B来查询这一行数据,它就要加读锁,读锁与写锁冲突,所以十五B、加锁不成功,它就必须等待事务A操作执行完毕释放写锁之后才能去进行读操作。

而有了 MVCC 的加入,我们的事务B再去查询该行数据时,就不需要等待事务A释放锁可以直接查询,查询方式是快照读(下面会解释到),查询到的是事务A修改数据之前当前行的数据,提高了数据库的并发效率。

总之一句话:MVCC 是通过数据行的多版本管理来实现数据库的并发控制,提高数据库的并发性能。

3. 快照读?当前读分别是什么?怎么理解?

3.1 快照读

我们姑且把刚才的事务A的查询操作理解为写操作,事务B的查询操作理解为读操作;在 MVCC 下,这里的读指的是快照读。了解在 Linux 操作系统和 Git 代码管理的大致应该清楚,我们可以通过 Linux 操作系统的快照将系统回溯到之前的某个版本,Git 也可以通过回溯版本返回至之前的某个代码版本。MVCC 中的快照与这两者大致意思相近,可以类比理解。

数据在修改之前和修改之后版本是不一样的,我们读取别人正在操作的数据时,可以读取该数据操作之前的快照,就可以避免读写锁互斥导致阻塞等待这一现象。

3.2 当前读

当前读就很好理解了,没有 MVCC 时,数据库是靠加锁来避免数据安全性问题,加的锁都是悲观锁。共享锁,排它锁都属于是当前读的一种范畴。

我们去读取数据,读取到的一定是当前数据,没有数据版本这一说法。假设要去读一个正在被修改的数据,是会阻塞的,只有别人修改完,才能去执行当前读这一操作,也可以理解为同步读。

4. 数据库的四种隔离级别

数据库有四种隔离级别。它们的隔离级别由低到高,并发能力由高到低。

没有 MVCC 的情况下

读未提交:解决了脏写问题;

读已提交:解决了脏写,脏读问题;

可重复读:解决了脏写,脏读,不可重复读;

串行化:    解决了脏写,脏读,不可重复读,幻读所有问题;

在有 MVCC 的情况下

可重复读:解决了脏写,脏读,不可重复读,幻读所有并发问题。数据库默认采用的也是可重复读,解决幻读正是因为采用了 MVCC 。

读已提交和可重复读的读数据方式采用的都是快照读的方式。读未提交则不可以,因为读未提交独到的就是最新的数据,无法使用快照;串行化也不可以,因为加锁的缘故,也无法使用快照。

5.  MVCC 实现原理

MVCC 实现原理主要依赖于三部分,隐藏字段,undo log版本链,readView。

5.1 隐藏字段

对于 InnoDB 存储引擎的表来说,它的聚簇索引记录(理解为每行数据即可)中都会有两个必要的隐藏字段 trx_id(事务id) 和 roll_pointer(回滚指针)。没有主键的表会有第三个额外的隐藏主键字段。隐藏字段的主要作用就是对每次数据操作进行标记区分并记录操作之前的数据的地址。

我就以下面这幅图来给各位解析一下 trx_id 和 roll_pointer.

trx_id:每次一个事务对聚簇索引的记录做改动,都会把该事务的事务id赋值给隐藏字段。

roll_pointer:每次对聚簇索引的记录做改动时,都会把旧的版本写入到 undo 日志中去,然后这个隐藏列相当于一个指针,可以通过它来找到该记录修改之前的数据。

如上图,假设与四个事务A,B,C,D。事务A插入数据,事务B,C,D均对插入的数据做了修改。四个事务在对数据进行增删改查的时候,数据库就会给这四个事务的隐藏字段 trx_id 以自增的方式赋值,这里 假设分别赋值为 1,2,3,4。

roll_pointer 回滚指针则是指向当前数据修改之前的数据值,倘若事务回滚,就会返回到之前的数据。

5.2 undo log(版本链)

如上所示四个事务进行的四次数据更新操作,每次数据操作之后,数据库都会把操作之前的旧值存放到 undo 日志中记录下来,随着更新次数的增多,每次记录都会由隐藏字段中的 roll_pointer 指针连接起来形成链表,所形成的链表我们就称之为版本链,链表的头节点就是当前数据最新的节点。

5.3 readView

刚才我们说到了版本链,既然一条数据经历了多次操作,有那么多个版本,我们在查询数据并进行操作的时候,是怎么知道该选择哪个版本的数据的呢?一定是查询操作最新的吗?这是不一定的。查询操作哪个版本的数据取决于我们的第三个重要元素 readView。

readView 就是事务在使用 MVCC 机制对数据库中的数据操作时产生的读视图。当事务开启之后,会生成数据库当前系统的一个快照,InnoDB 会为每个事务构建一个数组,用来记录并维护当前系统活跃事务的id (这里的活跃指代的是事务正在操作数据但是没有进行提交)。

6. readView 深层详解

readView 是MVCC 三个中最重要的组成部分,也是面试 MVCC 时经常问道的一个点。

readView 的核心原理主要体现在 READ COMMITTD(读已提交)和 REPEATABLE READ(可重复读) 两种隔离级别上。

READ COMMITTD:在每次进行 SELECT 查询操作的时候都会去生成一个 readView;

REPEATABLE READ:每开启一个事物才会生成一个 readView,一个事务的所有SQL语句共享一个 readView。

readView 有多个属性,m_ids 就可以理解为生成的数组记录,如下图所示,基于以下几种属性, 一共有四种可能情况。

情况一  trx_id == creator_trx_id:说明这条记录就是当前事务插入所形成的,自己插入的数据自己肯定可以访问;

情况二 trx_id < min_trx_id:    min_trx_id表示的是正在活跃的事务最小的 id,而所有活跃的事物都是未提交的,所以就可以查询得到,不会出现读未提交的情况;

情况三 trx_id > max_trx_id:   max_trx_id表示要分配给下一个事务的 id,二我们要查询的数据的 id 却比待分配的事物的 id 还要大,这是不可能查得到的。

情况四 min_trx_id <= trx_id <= max_trx_id:如果 trx_id 是在m_ids 中,则不可以访问这个版本,因为在此区间内则说明此当前事务正在进行中还没提交,不能访问其他事务未提交的数据,否则可能会产生脏读。如果不在m_ids  中,说明当前事务已经是 commit 提交过了的,则可以访问。

7. MVCC中是如何解决不可重复读的?

在 MVCC 中 可重复读的隔离级别下,它也解决了幻读。在 MVCC 下,它是给每一个事务生成一个 readView,整个事务的执行过程中用的都是同一个 readView。

举个最简单的例子,如下所示

(1)假设现在事务A与事务B并发操作来查询 student 表,事务A 执行查询操作,执行查询操作之前会生成一个 readView,我们姑且称之为 readView_1 ,事务A从始至终使用的都是 readView_1;

(2)此时事务B来修改 student 数据,又生成了一个 readView ,我们称之为 readView_2,然后事务B率先修改完毕并提交;

(3)事务A在事务B提交之后才进行的查询,按道理来说因为事务B修改了数据,我们会产生不可重复读,但是因为事务A从始至终都是用的 readView_1 ,所以 事务A在进行查询操作的时候,查询到的其实还是事务B修改之前的数据,由此就解决了不可重复读。

8. 间隙锁解决幻读问题(补充点)

刚才我已经解释过了 MVCC 中是如何解决不可重复读问题的,在 InnoDB 存储引擎中,幻读的问题也得到了解决,解决的方式是利用间隙锁;

还以下面这幅图举例说明

假设事务A与事务B并发执行,事务A要查询 id > 1的用户数据,那么在查询之前,数据库会对 id = 1 之后的区间加上间隙锁,也就是说在事务A执行期间,其他线程不可以在 id > 1 之后插入数据;当有其他操作想要插入数据时,会阻塞等待,只有事务A执行完毕释放了间隙锁,其他线程或者说事务才能进行插入操作,由此就避免了幻读的产生。

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

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

相关文章

1218. 最长定差子序列

1218. 最长定差子序列 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 1218. 最长定差子序列 https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/description/ 完成情况&#x…

低代码平台的坑有哪些?

大部分人/企业在选型的时候只会过分关注低代码平台所提供的功能&#xff0c;却忘记了“服务”同样重要。事实上&#xff0c;低代码的功能各家大差不差&#xff0c;基本都差不多。早前&#xff0c;我曾写过【低代码选型的注意事项】一文&#xff0c;今日不妨再说一嘴。 在研究低…

如何完美通过token获取用户信息(springboot)

1. 什么是Token&#xff1f; 身份验证令牌&#xff08;Authentication Token&#xff09;&#xff1a;在身份验证过程中&#xff0c;“token” 可以表示一个包含用户身份信息的令牌。 例如 Token&#xff08;JWT&#xff09;是一种常见的身份验证令牌&#xff0c;它包含用户的…

APP广告竞价机制:头部竞价与瀑布流

广告引擎竞价原理实际上就是平台如何从利用用户和广告主在平台的产生的活跃度时长&#xff0c;从两者本身产生价值中&#xff0c;赚取利润的原理。即平台在给广告主分发流量的过程中&#xff0c;引入付费广告概念&#xff0c;加速广告内容的曝光。 头部竞价与瀑布流 在瀑布流…

【ELK】日志分析系统概述及部署(ELFK部署实验)

目录 一、ELK概述 1、ELK是什么&#xff1f; 2、ELK的组成部分 2.1 ElasticSearch &#xff08;1&#xff09;分片和副本 &#xff08;2&#xff09;es和传统数据库的区别 2.2 Kiabana 2.3 Logstash &#xff08;1&#xff09;Log Stash主要组件 2.4 可添加的其它组件…

腾讯数据持久化方案MMKV原理分析

提到数据持久化存储的方案&#xff0c;Android提供的手段有很多&#xff0c;在项目中常用的就是SharedPreference(简称SP)&#xff0c;但是SP使用虽然简单&#xff0c;但是存在缺陷&#xff1a; 写入速度慢&#xff0c;尤其在主线程频繁执行写入操作易导致卡顿或者ANR&#xf…

Python 基于PyCharm断点调试

视频版教程 Python3零基础7天入门实战视频教程 PyCharm Debug&#xff08;断点调试&#xff09;可以帮助开发者在代码运行时进行实时的调试和错误排查&#xff0c;提高代码开发效率和代码质量。 准备一段代码 def add(num1, num2):return num1 num2if __name__ __main__:f…

剧情反转 抵制AI音乐的华纳签了位虚拟歌手

从文字、图片、视频到语音、音乐&#xff0c;AIGC已经渗入到人类的视听体验中&#xff0c;即便曾经因为版权问题极力抵制AI音乐的巨头&#xff0c;也不得不转变态度顺应时代产物。 今年9月&#xff0c;华纳音乐签约了首个虚拟歌手Noonoouri&#xff1b;8月&#xff0c;环球音乐…

Reids Cluster集群部署

服务器端口说明 vim /etc/hosts 1.下载、解压、编译Redis $ mkdir -p /opt/redis && cd /opt/redis $ wget http://download.redis.io/releases/redis-6.0.6.tar.gz $ tar xzf redis-6.0.6.tar.gz 请先检查gcc的版本是否低于5&#xff0c;如果是请先升级&#xff0c…

Java基础实战:Java中的引用类型(强软弱虚)

下面是一个在下面引用实战中用到的公共类 public class M {Overrideprotected void finalize() throws Throwable{System.out.println("finalize");} }finalize()方法是执行gc时调用的方法。 一、强引用 强引用是默认的引用类型。当一个对象具有强引用时&#xff…

深度学习-经典网络解析-VGG-[北邮鲁鹏]

这里写目录标题 VGG参考VGG网络贡献使用尺寸更小的 3 3 3 \times 3 33卷积串联来获得更大的感受野放弃使用 11 11 11 \times 11 1111和 5 5 5 \times 5 55这样的大尺寸卷积核深度更深、非线性更强&#xff0c;网络的参数也更少&#xff1b;去掉了AlexNet中的局部响应归一化层…

大模型赛道如何实现华丽的弯道超车【赠书活动|第十期《分布式统一大数据虚拟文件系统 Alluxio原理、技术与实践》】

文章目录 01 具备对海量小文件的频繁数据访问的 I/O 效率02 提高 GPU 利用率&#xff0c;降低成本并提高投资回报率03 支持各种存储系统的原生接口04 支持单云、混合云和多云部署01 通过数据抽象化统一数据孤岛02 通过分布式缓存实现数据本地性03 优化整个工作流的数据共享04 通…

【Java实战项目】【超详细过程】—— 大饼的图片服务器

目录 一.下载前端模板二. 展示图片&#xff08;index.htmll&#xff09;1. 标题2. 页面跳转链接3. 图片展示引入js和vue依赖&#xff1a;写在html文件的head中js代码&#xff1a;写在html文件中的body中html代码&#xff1a;写在html文件的body中 二. 删除图片在上面的vue对象a…

【OWASP如何导出测试报告】

为什么我的OWASP无法导出报告&#xff1f;明明已经扫描完成了

【Linux从入门到精通】多线程 | 线程介绍线程控制

本篇文章主要对线程的概念和线程的控制进行了讲解。其中我们再次对进程概念理解。同时对比了进程和线程的区别。希望本篇文章会对你有所帮助。 文章目录 一、线程概念 1、1 什么是线程 1、2 再次理解进程概念 1、3 轻量级进程 二、进程控制 2、1 创建线程 pthread_create 2、2…

Postgresql与执行计划相关的配置项

1. ENABLE_*参数 在PostgreSQL中有一些以“ENABLE_”开头的参数&#xff0c;这些参数提供了影响查询优化器选择不同执行计划的方法。有时&#xff0c;如果优化器为特定查询选择的执行计划并不是最优的&#xff0c;可以设置这些参数强制优化器选择一个更好的执行计划来临时解决这…

java开发之个微朋友圈机器人的开发

简要描述&#xff1a; 取消点赞 请求URL&#xff1a; http://域名地址/snsCancelPraise 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明…

分子对接简介-2023

分子对接简介-2023 分子对接&#xff08;Molecular Docking&#xff09;是分子模拟的重要方法之一&#xff0c;其本质是两个或多个分子之间的识别过程&#xff0c;其过程涉及分子之间的空间匹配和能量匹配。这项技术在药物研发、生物医学研究和药物设计中具有广泛的应用&#…

简明 SQL 组合查询指南:掌握 UNION 实现数据筛选

在SQL中&#xff0c;组合查询是一种将多个SELECT查询结果合并的操作&#xff0c;通常使用UNION和UNION ALL两种方式。 UNION 用于合并多个查询结果集&#xff0c;同时去除重复的行&#xff0c;即只保留一份相同的数据。UNION ALL 也用于合并多个查询结果集&#xff0c;但不去除…

MapRdeuce工作原理

hadoop - (三)通俗易懂地理解MapReduce的工作原理 - 个人文章 - SegmentFault 思否 MapReduce架构 MapReduce执行过程 Map和Reduce工作流程 (input) ->map-> ->combine-> ->reduce-> (output) Map&#xff1a; Reduce