【MySQL系列笔记】MVCC

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。在 RC、RR 这两种隔离级别下生效。在事务也提到,MVCC是保证MySQL在默认隔离级别RR情况下,针对快照读解决幻读问题。而针对当前读需要隔离锁的临键锁(记录锁+间隙锁)去解决。

1. 概述

并发事务会有 脏写、脏读、不可重复读、幻读 四个问题,脏写可以通过乐观锁或悲观锁的方式来解决,脏读、不可重复读、幻读 三个问题通过事务的隔离性来解决。

脏读、不可重复读、幻读 说的都是并发读取的问题,最简单的方式就是给记录加一把锁,不管是更新、读取记录都需要竞争到这把锁之后才能操作。但这种方式的并发性能可想而知会有多么低。

于是 InnoDB 就设计了MVCC来解决并发读取的问题。先来了解一些基本概念。

1.1. 当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读。

1.2. 快照读

简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

• Read Committed:每次select,都生成一个快照读。

• Repeatable Read:开启事务后第一个select语句才是快照读的地方。

• Serializable:快照读会退化为当前读。

1.3. MVCC

全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。

MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。在 RC、RR 这两种隔离级别下生效。

在事务也提到,MVCC是保证MySQL在默认隔离级别RR情况下,针对快照读解决幻读问题。而针对当前读需要隔离锁的临键锁(记录锁+间隙锁)去解决。

2. 隐藏字段

在表结构中,除了可以查看的显式字段(设计表时输入的字段),InnoDB还会自动的给我们添加三个隐藏字段。分别是

隐藏字段

含义

db_trx_id

最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。

db_roll_ptr

回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。

db_row_id

隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

前两个字段是肯定会添加的, 是否添加最后一个字段DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。

查看stu的表结构信息。查看到的表结构信息中,有一栏 columns,在其中我们会看到处理我们建表时指定的字段以外,还有额外的两个字段 分别是:DB_TRX_ID 、 DB_ROLL_PTR ,因为该表有主键,所以没有DB_ROW_ID隐藏字段。

ibd2sdi table.ibd

3. undolog

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

3.1. 版本链

有一张表原始数据如下,并且有四个并发事务同时在访问这张表。

db_trx_id : 代表最近修改事务id,记录插入这条记录或最后一次修改该记录的事务id,是自增的。

db_roll_ptr : 由于这条数据是才插入的,没有被更新过,所以该字段值为null。

3.2. 执行流程

  1. 当事务2执行第一条修改语句时,会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

  1. 当事务3执行第一条修改语句时,也会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

  1. 当事务4执行第一条修改语句时,也会记录undo log日志,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。

最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

4. readview

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

4.1. 核心字段

ReadView中包含了四个核心字段:

字段

含义

m_ids

当前活跃的事务ID集合

min_trx_id

最小活跃事务ID

max_trx_id

预分配事务ID,即未开始的事务;当前最大事务ID+1(因为事务ID是自增的)

creator_trx_id

ReadView创建者的事务ID

4.2. 访问规则

而在readview中就规定了版本链数据的访问规则,按照下面的顺序访问;

其中trx_id 代表当前undolog版本链对应事务ID。

条件

是否可以访问

说明

trx_id == creator_trx_id

可以访问该版本

成立,说明数据是当前这个事务更改的。

trx_id < min_trx_id

可以访问该版本

成立,说明数据已经提交了。

trx_id > max_trx_id

不可以访问该版本

成立,说明该事务是在ReadView生成后才开启。

min_trx_id <= trx_id <= max_trx_id

如果trx_id不在m_ids中,是可以访问该版本的

成立,说明数据已经提交。

不同的隔离级别,生成ReadView的时机不同:

  • READ COMMITTED :在事务中每一次执行快照读时生成ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

5. MVCC原理

5.1. 执行流程

有了ReadView后,在事务中查询的时候,就可以沿着 undo 版本链查找当前事务可见的版本。这时 undo log 中的隐藏列 trx_id 就派上用场了,它表示产生这条 undo log 时的事务的事务ID。判断此版本是否可访问的依据就是用 undo log 中的 trx_id 属性值与 ReadView 中的各个属性做比较。

通过如下步骤来判断版本是否可被访问:

  • ① 如果 trx_id 等于 creator_trx_id ,说明当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  • ② 如果 trx_id 小于 min_trx_id,说明生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问。
  • ③ 如果 trx_id 大于或等于max_trx_id,说明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。
  • ④ 如果 trx_idmin_trx_idmax_trx_id 之间,此时再判断一下 trx_id 是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

大致的流程图如下:

5.2. 总结

从上面示例的演示过程就可以看出,MVCC 就是通过 undo log 版本链 + ReadView 实现的一套并发读取的机制。

READ COMMITTD 隔离级别下,每次查询都生成一个新的 ReadView,不能读到别的事务未提交的修改,因此解决了 脏读 的问题。但是能读取到别的事务已提交的修改,会有 不可重复读、幻读 的问题。

REPEATABLE READ 隔离级别下,只在第一次查询时生成一个 ReadView,之后的查询都重复使用这个 ReadView。别的事务未提交、已提交、新插入的修改都读取不到,因此解决了 脏读、不可重复读、幻读 的问题。

执行 DELETE 语句或者更新主键的 UPDATE 语句并不会立即把对应的记录完全从页面中删除,而是将 delete_mask 设置为 1,做标记删除。这时就清楚是为什么了,这主要就是为MVCC服务的,因为可能有其它并发运行的事务,要通过版本链读取当前事务可见的版本。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
16天前
|
SQL 存储 关系型数据库
【MySQL系列笔记】事务
事务是数据库操作的序列,确保一组操作要么全部成功要么全部失败。它们具有原子性、一致性、隔离性和持久性(ACID)特性。原子性保证事务中的所有操作不可分割,一致性确保事务前后数据库状态符合业务规则,隔离性防止并发事务间数据交错,持久性则指事务提交后结果永久保存。MySQL的InnoDB引擎支持四种隔离级别,包括读未提交、读已提交、可重复读和串行化,以平衡并发性能和数据一致性。默认的可重复读级别通过MVCC避免幻读问题。事务可通过开始、提交、回滚命令管理,并有扁平、带有保存点、链式、嵌套和分布式等多种类型。并发事务可能导致脏读、不可重复读和幻读等问题,通过锁和隔离级别来解决。
154 4
|
2月前
|
存储 SQL 关系型数据库
MySQL - 深入理解 MySQL 的 MVCC 及实现原理
MySQL - 深入理解 MySQL 的 MVCC 及实现原理
195 0
|
7月前
|
SQL 算法 关系型数据库
到底什么是Mysql的MVCC
到底什么是Mysql的MVCC
|
9月前
|
存储 关系型数据库 MySQL
【MySQL面试】说说MVCC
【MySQL面试】说说MVCC
194 0
|
9月前
|
存储 算法 Oracle
MVCC在Mysql中的运用
MVCC在Mysql中的运用
53 0
|
10月前
|
存储 SQL 安全
一文读懂 Mysql MVCC
MVCC(Multi-Version Concurrency Control)是一种**多版本并发控制**技术,常用于数据库管理系统中,用于支持事务的并发执行。MVCC 技术可以在读取数据时不产生锁,同时保证数据的一致性。具体来说,MVCC 技术会在每个数据行上保存多个版本的数据,每个版本都有一个时间戳,当一个事务需要读取数据时,会根据该事务的时间戳选择合适的数据版本进行读取,从而避免了读取数据时的锁定操作。同时,MVCC 技术还可以通过回滚日志和垃圾回收机制来保证数据的一致性和完整性。MVCC 技术在 InnoDB 存储引擎中得到了广泛的应用,成为了 InnoDB 存储引擎的一个重要特性
295 1
一文读懂 Mysql MVCC
|
关系型数据库 MySQL
Mvcc--mysql详解(十一)
Mvcc--mysql详解(十一)
|
存储 缓存 关系型数据库
一文理解Mysql MVCC
就是多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。
一文理解Mysql MVCC
|
SQL 存储 Oracle
MySQL中的MVCC是怎么实现的,你们知道吗?
不晓得大家了解不了解MySQL的MVCC机制,这个是MySQL底层原理中比较重要的一项,它能极大的提高MySQL数据库的并发性能。MVCC广泛应用于数据库技术,像Oracle,PostgreSQL等都引入了该技术。本篇文章我们就带大家一起了解一下MySQL的MVCC机制实现原理。
271 0
|
SQL 存储 安全
MySQL 8.0 MVCC 源码解析
本文在此基础上,对 MVCC 展开详细的分析,同时修改了之前的一些不太准确的说法,希望可以助你在面试中更好的发(zhuang)挥(bi)。
517 0
MySQL 8.0 MVCC 源码解析