值得收藏,揭秘 MySQL 多版本并发控制实现原理

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: MySQL 中多版本并发控制(MVCC),是现代数据库引擎实现中常用的处理读写冲突的手段,MVCC 作为 MySQL 高级应用特性,目的在于提高数据库高并发场景下的吞吐性能。


MySQL 中多版本并发控制(MVCC),是现代数据库引擎实现中常用的处理读写冲突的手段,MVCC 作为 MySQL 高级应用特性,目的在于提高数据库高并发场景下的吞吐性能。


一、MVCC出现背景是什么?


事务的4个隔离级别以及对应的3种异常:


微信图片_20220608223435.png


  • 脏读:一个事务读取到了另外一个事务没有提交的数据;


  • 不可重复读:在同一事务中,两次读取同一数据,得到内容不同;


  • 幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同。


在 MySQL 中,默认的隔离级别是可重复读,可以解决脏读和不可重复读的问题,但不能解决幻读问题。如果我们想要解决幻读问题,就需要采用串行化的方式,也就是将隔离级别提升到最高,但这样一来就会大幅降低数据库的事务并发能力。而MVCC就是通过乐观锁的方式来解决不可重复读和幻读问题,它可以在大多数情况下替代行级锁,降低系统的开销。MySQL 并发事务会引起更新丢失问题,解决办法是锁,主要分两类:


  • 乐观锁:


其实现如同它的名字一样,是假设比较好的情况。


每次取数据的时候都认为他人不会对其修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。


  • 悲观锁:


悲观锁也如同它的名字一样,总是假设比较坏的情况,每次取数据的时候都认为他人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。


二、什么是MVCC,它解决了什么问题?


MVCC 是通过数据行的多个版本管理来实现数据库的并发控制,简单来说它的思想就是保存数据的历史版本。


我们可以通过比较版本号决定数据是否显示出来(具体的规则后面会介绍到),读取数据的时候不需要加锁也可以保证事务的隔离效果。


通过 MVCC 我们可以解决以下几个问题:


(1)读写之间阻塞的问题,通过 MVCC 可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。


(2)降低了死锁的概率。这是因为 MVCC 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。


(3)解决一致性读的问题。一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。解释一下可能难以理解的几个词汇:


  • 快照读:


读取的是快照数据,不加锁的简单的SELECT都属于快照读(只是普通的读操作)。


  • 当前读:


当前读就是读取最新数据,而不是历史版本的数据。
加锁的SELECT,或者对数据进行增删改都会进行当前读(包括加锁的读取和DML操作)。


三、应用举例分析


为了更好地让大家理解MVCC,我们用一个示例场景来说明。假设有个账户金额表 user_balance,包括三个字段,分别是 username 用户名、balance 余额和 bankcard 卡号,表数据如下所示:

微信图片_20220608223438.png用户 A 和用户 B 之间进行转账,此时数据库管理员想要查询 user_balance 表中的总金额,两个场景存在并发情况,在没有MVCC的情况下,会出现哪些问题呢。Case1:因为需要采用加行锁的方式,用户 A 给 B 转账时间等待很久,如下图所示。


微信图片_20220608223440.png


Case2:当我们读取的时候用了加行锁,可能会出现死锁的情况,如下图所示。


微信图片_20220608223443.png


比如当我们读到 A 有 1000 元的时候,此时 B 开始执行给 A 转账。


四、InnoDB如何实现MVCC?


当查询一条记录的时候,执行流程如下:


  1. 首先获取事务自己的版本号,也就是事务 ID;


  1. 获取 Read View;


  1. 查询得到的数据,然后与 Read View 中的事务版本号进行比较;


  1. 如果不符合 ReadView 规则,就需要从 Undo Log 中获取历史快照;


  1. 最后返回符合规则的数据。


相关概念


1. 事务版本号一个自增长的事务ID,用于标记事务执行的先后顺序。


2. Read View在 MVCC 机制中,多个事务对同一个行记录进行更新会产生多个历史快照,这些历史快照保存在 Undo Log 里。如果一个事务想要查询这个行记录,需要读取哪个版本的行记录呢?这时就需要用到 Read View 了,它帮我们解决了行的可见性问题。Read View 保存了当前事务开启时所有活跃(还没有提交)的事务列表,换个角度,可以理解为 Read View 保存了不应该让这个事务看到的其他的事务 ID 列表。Read VIew 中的几个重要属性:


微信图片_20220608223446.png

  • up_limit_id,活跃的事务中最小的事务 ID;


  • trx_ids,系统当前正在活跃的事务 ID 集合;


  • low_limit_id,活跃的事务中最大的事务 ID;


  • creator_trx_id,创建这个 Read View 的事务 ID。


3. 行记录的隐藏列InnoDB 的叶子节点段存储了数据页,数据页中保存了行记录,在这些行记录中有一些重要的隐藏字段:


  • DB_ROW_ID :


6-byte,记录操作该数据事务的事务ID;


  • DB_TRX_ID :


6-byte,当创建表没有合适的索引作为聚集索引时,会用该隐藏ID创建聚集索引;


  • DB_ROLL_PTR :


7-byte,回滚指针,指向上一个版本数据在undo log 里的位置指针;


4. 聚集索引聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况,所以,对应的聚集索引只能有一个。


5. Undo LogInnoDB 将行记录快照保存在 Undo Log,可以在回滚段中找到它们,主要用于记录数据被修改之前的日志,在对表信息做修改之前先会把数据拷贝到Undo Log里,当事务进行回滚时可以通过Undo Log里的日志进行数据还原。回滚段中回滚指针间关联关系,如下图所示:

微信图片_20220608223449.png


五、InnoDB是如何解决幻读的?


1、在读已提交的情况下,即使采用了 MVCC 方式也会出现幻读


微信图片_20220608223452.png

我们同时开启事务 A 和事务 B,先在事务 A 中进行某个条件范围的查询,读取的时候采用排它锁,在事务 B 中增加一条符合该条件范围的数据,并进行提交,然后我们在事务 A 中再次查询该条件范围的数据,就会发现结果集中多出一个符合条件的数据,这样就出现了幻读。


出现幻读的原因是在读已提交的情况下,InnoDB 只采用记录锁(Record Locking)。InnoDB 三种行锁的方式:


  • 记录锁:


针对单个行记录添加锁。


  • 间隙锁(Gap Locking):


可以锁住一个范围(索引之间的空隙),但不包括记录本身。


采用间隙锁的方式可以防止幻读情况的产生。


  • Next-Key 锁:


锁住一个范围,同时锁定记录本身,相当于间隙锁 + 记录锁,可以解决幻读的问题。


2、在可重复读的情况下,InnoDB 可以通过 Next-Key 锁 +MVCC 来解决幻读问题。想插入球员艾利克斯·伦(身高 2.16 米)的时候,事务 B 会超时,无法插入该数据。这是因为采用了 Next-Key 锁,会将 height>2.08 的范围都进行锁定,就无法插入符合这个范围的数据了。然后事务 A 重新进行条件范围的查询,就不会出现幻读的情况。


微信图片_20220608223455.png


六、总结


MVCC 的核心就是 Undo Log+ Read View。


  • “MV”就是通过 Undo Log 来保存数据的历史版本,实现多版本的管理;


  • “CC”是通过 Read View 来实现管理,通过 Read View 原则来决定数据是否显示。


同时针对不同的隔离级别,Read View 的生成策略不同,也就实现了不同的隔离级别。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
677
分享
相关文章
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
MySQL实现文档全文搜索,分词匹配多段落重排展示,知识库搜索原理分享
本文介绍了在文档管理系统中实现高效全文搜索的方案。为解决原有ES搜索引擎私有化部署复杂、运维成本高的问题,我们转而使用MySQL实现搜索功能。通过对用户输入预处理、数据库模糊匹配、结果分段与关键字标红等步骤,实现了精准且高效的搜索效果。目前方案适用于中小企业,未来将根据需求优化并可能重新引入专业搜索引擎以提升性能。
219 5
MySQL进阶突击系列(03) MySQL架构原理solo九魂17环连问 | 给大厂面试官的一封信
本文介绍了MySQL架构原理、存储引擎和索引的相关知识点,涵盖查询和更新SQL的执行过程、MySQL各组件的作用、存储引擎的类型及特性、索引的建立和使用原则,以及二叉树、平衡二叉树和B树的区别。通过这些内容,帮助读者深入了解MySQL的工作机制,提高数据库管理和优化能力。
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
随着数据量增长和业务扩展,单个数据库难以满足需求,需调整为集群模式以实现负载均衡和读写分离。MySQL主从复制是常见的高可用架构,通过binlog日志同步数据,确保主从数据一致性。本文详细介绍MySQL主从复制原理及配置步骤,包括一主二从集群的搭建过程,帮助读者实现稳定可靠的数据库高可用架构。
335 9
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
3433 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
vb6读取mysql,用odbc mysql 5.3版本驱动
通过以上步骤,您可以在VB6中使用ODBC MySQL 5.3驱动连接MySQL数据库并读取数据。配置ODBC数据源、编写VB6代码
144 32
MySQL主从复制 —— 作用、原理、数据一致性,异步复制、半同步复制、组复制
MySQL主从复制 作用、原理—主库线程、I/O线程、SQL线程;主从同步要求,主从延迟原因及解决方案;数据一致性,异步复制、半同步复制、组复制
549 11
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
237 7
MySQL事务日志-Undo Log工作原理分析
MySQL进阶突击系列(08)年少不知BufferPool核心原理 | 大哥送来三条大金链子LRU、Flush、Free
本文深入探讨了MySQL中InnoDB存储引擎的buffer pool机制,包括其内存管理、数据页加载与淘汰策略。Buffer pool作为高并发读写的缓存池,默认大小为128MB,通过free链表、flush链表和LRU链表管理数据页的存取与淘汰。其中,改进型LRU链表采用冷热分离设计,确保预读机制不会影响缓存公平性。文章还介绍了缓存数据页的刷盘机制及参数配置,帮助读者理解buffer pool的运行原理,优化MySQL性能。

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问