硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

1. 什么是MVCC

MVCC全称是 Multi-Version Concurrency Control(多版本并发控制),是一种并发控制的方法,通过维护一个数据的多个版本,减少读写操作的冲突。

如果没有 MVCC,想要实现同一条数据的并发读写,还要保证数据的安全性,就需要操作数据的时候加读锁和写锁,这样就降低了数据库的并发性能。

有了 MVCC,就相当于把同一份数据生成了多个版本,在操作的开始各生成一个快照,读写操作互不影响。无需加锁,也实现数据的安全性和事务的隔离性。

事务的四大特性中隔离性就是基于 MVCC实现的。

说MVCC的实现原理之前,先说一下事务的隔离级别。

2. 事务的隔离级别

说隔离级别之前,先说一下 并发事务产生的问题

脏读: 一个事务读到其他事务未提交的数据。

不可重复读: 相同的查询条件,多次查询到的结果不一致,即读到其他事务提交后的数据。

幻读: 相同的查询条件,多次查询到的结果不一致,即读到其他事务提交后的数据。

不可重复读与幻读的区别是: 不可重复读是读到了其他事务执行update、delete后的数据,而幻读是读到其他事务执行insert后的数据。

再说一下事务的四大隔离级别:

Read UnCommitted(读未提交): 读到其他事务未提交的数据,会出现脏读、不可重复读、幻读。

Read Committed(读已提交): 读到其他事务已提交的数据,解决了脏读,会出现不可重复读、幻读。

Repeatable Read(可重复读): 相同的条件,多次读取到的结果一致。解决了脏读、不可重复读,会出现幻读。

Serializable(串行化): 所有事务串行执行,解决了脏读、不可重复读、幻读。

隔离级别 脏读 不可重复读 幻读 读未提交 会 会 会 读已提交 不会 会 会 可重复读 不会 不会 会 串行化 不会 不会 不会

MVCC只在 Read CommittedRepeatable Read两个隔离级别下起作用,因为 Read UnCommitted隔离级别下,读写都不加锁, Serializable隔离级别下,读写都加锁,也就不需要 MVCC了。

再谈一下 Undo log日志。

3. Undo Log(回滚日志)

Undo Log记录的是逻辑日志,也就是SQL语句。

比如:当我们执行一条insert语句时, Undo Log就记录一条相反的delete语句。

作用:

  1. 回滚事务时,恢复到修改前的数据。
  2. 实现 MVCC

事务四大特性中原子性也是基于 Undo Log实现的。

下面开始谈一下 MVCC的实现原理。

4. MVCC的实现原理

4.1 当前读和快照读

先普及一下什么是当前读和快照读。

当前读: 读取数据的最新版本,并对数据进行加锁。

例如:insert、update、delete、select for update、 select lock in share mode。

快照读: 读取数据的历史版本,不对数据加锁。

例如:select

MVCC是基于Undo Log、隐藏字段、Read View(读视图)实现的。

4.2 隐藏字段

先说一下MySQL的隐藏字段,当我们创建一张表时,InnoDB引擎会增加2个隐藏字段。

DB_TRX_ID(最近一次提交事务的ID):修改表数据时,都会提交事务,每个事务都有一个唯一的ID,这个字段就记录了最近一次提交事务的ID。

DB_ROLL_PTR(上个版本的地址):修改表数据时,旧版本的数据都会被记录到Undo Log日志中,每个版本的数据都有一个版本地址,这个字段记录的就是上个版本的地址。

4.3 版本链

当我们第一次往用户表插入一条记录时,表数据和隐藏字段的值是下面这样的:

insert into user (name,age) values ('一灯',1);

事务ID(DB_TRX_ID)是1,上个版本地址(DB_ROLL_PTR)是null。

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

第二次提交事务,把用户年龄加1。

update user set age=age+1 where id=1;

事务ID变成2,上个版本地址指向Undo Log中的记录。

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

第三次提交事务,再把用户年龄加1。

update user set age=age+1 where id=1;

事务ID变成3,上个版本地址指向Undo Log中事务ID为2的记录。

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

这样表记录和 Undo Log历史数据就组成了一个版本链。

4.4 Read View(读视图)

在事务中,执行SQL查询,就会生成一个读视图,是用来保证数据的可见性,即读到Undo Log中哪个版本的数据。

快照读一般是读取的历史版本的读视图, 当前图会生成一个最新版本的读视图。

读视图是基于下面几个字段实现的:

m_ids :当前系统中活跃的事务ID集合,即未提交的事务。

min_trx_id :m_ids中最小的ID

max_trx_id :下一个要分配的事务ID

creator_trx_id: 当前事务ID

读视图决定当前事务能读到哪个版本的数据,从表记录到 Undo Log历史数据的版本链,依次匹配,满足哪个版本的匹配规则,就能读到哪个版本的数据,一旦匹配成功就不再往下匹配。

数据可见性规则:

  1. DB_TRX_ID = creator_trx_id
    如果这个版本数据的事务ID等于当前事务ID,表示数据记录的最后一次操作的事务就是当前事务,当前读视图可以读到这个版本的数据。
  2. DB_TRX_ID < min_trx_id
    如果这个版本数据的事务ID小于所有活跃事务ID,表示这个版本的数据不再被事务使用,即事务已提交,当前读视图可以读到这个版本的数据。
  3. DB_TRX_ID >= max_trx_id
    如果这个版本数据的事务ID大于等于下一个要分配的事务ID,表示有新事务更新了这个版本的数据,这种情况下,当前读视图不可以读到这个版本的数据。
  4. min_trx_id

5. 不同隔离级别下可见性分析

在不同的事务隔离级别下,生成读视图的规则不同:

  • READ COMMITTED(读已提交) :在事务中每一次执行快照读时都生成一个读视图,每个读视图中四个字段的值都是不同的。
  • REPEATABLE READ(可重复读):仅在事务中第一次执行快照读时生成读视图,后续复用这个读视图。

5.1 READ COMMITTED(读已提交)

设置MySQL隔离级别为读已提交:

SET session TRANSACTION ISOLATION LEVEL READ COMMITTED;

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

执行两个事务,验证一下:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

事务1第一次查询时,会生成一个读视图,读视图的各个属性如下:

属性 值 m_ids 1,2 min_limit_id 1 max_limit_id 3 creator_trx_id 1

可见的版本链数据是:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

符号规则 DB_TRX_ID = creator_trx_id = 1,可以看到当前版本的数据。

事务1第二次查询时,会生成一个新的读视图,读视图的各个属性如下:

属性 值 m_ids 1 min_limit_id 1 max_limit_id 3 creator_trx_id 1

可见的版本链数据是:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

符号规则 min_trx_id <= db_trx_id < max_trx_id(1<="2<3&#xFF09;</code">&#xFF0C;&#x5E76;&#x4E14;&#x5F53;&#x524D;&#x6570;&#x636E;&#x7248;&#x672C;&#x7684;&#x4E8B;&#x52A1;ID&#x4E0D;&#x5728;&#x5F53;&#x524D;&#x7CFB;&#x7EDF;&#x4E2D;&#x6D3B;&#x8DC3;&#x7684;&#x4E8B;&#x52A1;ID&#x96C6;&#x5408;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x5F53;&#x524D;&#x7248;&#x672C;&#x7684;&#x6570;&#x636E;&#x3002;<!--=-->

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

同一个事务内,相同的查询条件,查询到的数据不一致,查到了其他事务更新过的数据,也就是出现了不可重复读的情况。

再看一下,在可重复读隔离级别下,是怎么解决这个问题的。

5.2 REPEATABLE READ(可重复读)

设置MySQL隔离级别为可重复读:

SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

执行两个事务,验证一下:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

事务1第一次查询时,会生成一个读视图,读视图的各个属性如下:

属性 值 m_ids 1,2 min_limit_id 1 max_limit_id 3 creator_trx_id 1

可见的版本链数据是:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

符号规则 DB_TRX_ID = creator_trx_id = 1,可以看到当前版本的数据。

事务1第二次查询时,会复用原有的读视图,读视图的各个属性如下:

属性 值 m_ids 1,2 min_limit_id 1 max_limit_id 3 creator_trx_id 1

可见的版本链数据是:

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

符号规则 min_trx_id <= db_trx_id < max_trx_id(1<="2<3&#xFF09;</code">&#xFF0C;&#x5E76;&#x4E14;&#x5F53;&#x524D;&#x6570;&#x636E;&#x7248;&#x672C;&#x7684;&#x4E8B;&#x52A1;ID&#x5728;&#x5F53;&#x524D;&#x7CFB;&#x7EDF;&#x4E2D;&#x6D3B;&#x8DC3;&#x7684;&#x4E8B;&#x52A1;ID&#x96C6;&#x5408;&#xFF0C;&#x6240;&#x4EE5;&#x662F;&#x4E0D;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x5F53;&#x524D;&#x7248;&#x672C;&#x7684;&#x6570;&#x636E;&#x3002;<!--=-->

硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

由此得知,可重复读隔离级别下,相同的查询条件,两次查询到的结果相同,也就是解决了可重复读的问题,是通过复用原有的读视图的方式解决的。

Original: https://www.cnblogs.com/yidengjiagou/p/16663224.html
Author: 一灯架构
Title: 硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/586934/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 踩坑系列-Java Calendar

    Calendar是Java util包下的日期Api,其中获取月份是当前月份-1 java;gutter:true; public class Demo {</p> &…

    Java 2023年6月7日
    070
  • SQL

    1.between匹配 包含min和max值 count(*) 计算时会包括null值,而count(column)则会忽略null值。 检验是否含有null值需要使用is nul…

    Java 2023年6月9日
    072
  • session和cookie的区别

    一·概念理解 首先呢,要了解session和cookie的区别先要了解以下几个概念: 1、 无状态的HTTP协议: 协议,是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的…

    Java 2023年6月14日
    072
  • 几大,几届,几中 常识

    “几大”是指? 党的几大,是指党的全国代表大会。 按照《中国共xx章程》规定,党的全国代表大会每五年举行一次,我们通常简称为”**大&#8221…

    Java 2023年6月5日
    075
  • nginx -s reload 与 service nginx restart 的区别

    官方文档:https://nginx.org/en/docs/beginners_guide.html 1. 语法nginx -s signal signal 的值如下:stop:…

    Java 2023年5月30日
    099
  • 朱晔和你聊Spring系列S1E11:小测Spring Cloud Kubernetes @ 阿里云K8S

    朱晔和你聊Spring系列S1E11:小测Spring Cloud Kubernetes @ 阿里云K8S 有关Spring Cloud Kubernates(以下简称SCK)详见…

    Java 2023年5月30日
    070
  • 使用Animate.css

    Animate.css是一个css动画库,可以做出一些非常好看的动画; 官网:https://animate.style Animate.css非常容易上手,但是动画是一开始就加载…

    Java 2023年6月6日
    095
  • 【SpringCloud-Alibaba系列教程】7.容错

    一丶背景 在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个…

    Java 2023年6月5日
    084
  • 72.有人

    dsfd posted @2022-09-28 08:48 随遇而安== 阅读(42 ) 评论() 编辑 Original: https://www.cnblogs.com/55z…

    Java 2023年6月7日
    074
  • 微服务的架构发展(转载)

    微服务介绍 微服务(或微服务架构)是一种云原生架构方法,其中单个应用程序由许多松散耦合且可独立部署的较小组件或服务组成。这些服务通常有自己的堆栈,包括数据库和数据模型;通过REST…

    Java 2023年6月5日
    062
  • 并发QPS公式估算

    一、经典公式1: 一般来说,利用以下经验公式进行估算系统的平均并发用户数和峰值数据 1)平均并发用户数为 C = nL/T 2)并发用户数峰值 C’ = C + 3*根…

    Java 2023年6月15日
    070
  • Java生成二维码

    1,下载jar包(QRCode.jar) maven依赖 <span> <span><groupid><span>QRCode&lt…

    Java 2023年5月29日
    082
  • Css3入门详解

    一、Css基本语法 1.Html和Css没分开 点击查看代码 <!DOCTYPE html> <html lang="en"> <…

    Java 2023年6月13日
    070
  • 设计模式 09 组合模式

    组合模式(Composite Pattern)属于 结构型模式 概述 组合模式实际上就是将多个组件进行组合,让用户可以对它们进行一致性处理。 比如文件夹,一个文件夹中可能包含有很多…

    Java 2023年6月6日
    0124
  • Spring是如何解决循环依赖(引用)的?

    首先什么是循环依赖,比如A->B->A,正常我们普通的类怎么解决呢,就是先 new A(),new B() ,然后再 setB,setA ,也比较好解决。 那么大家为什…

    Java 2023年6月5日
    076
  • 【干货】整理分布式技术框架常用的算法及策略

    将一些零散的知识点进行整理, 以便加深理解,方便查阅,也希望能帮到大家。 通过系统随机函数,根据后端服务器列表的大小值来随机选择其中一台进行访问。由概率统计理论可以得知,随着调用量…

    Java 2023年6月9日
    067
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球