您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
MySQL的MVCC介绍
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
MySQL的MVCC介绍
自猿其说Tech
2022-09-19
IP归属:未知
20760浏览
数据库
MySQL
### 1 前言 我们知道在事务并发执行中,为了解决读写冲突可以使用加锁的方式,但加锁会降低性能。MySQL的InnoDB中为了提高数据库并发性能,用更好的方式去处理读-写冲突,使用了MVCC来实现不加锁的非阻塞并发读。下面我们来了解下MVCC。 ### 2 MVCC MVCC (Multi-Version Concurrency Control) 多版本并发控制, 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。 在MySQL中是通过3个隐式字段、undo日志、Read View来实现的MVCC。 #### 2.1 3个隐式字段 在MySQL的InnoDB实现中,每行记录除了自定义的字段,数据库会隐式的额外定义DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID 三个字段 - DB_TRX_ID,最近修改(修改/插入)事务 ID,记录创建这条记录或最后一次修改该记录的事务 ID; - DB_ROLL_PTR,回滚指针,指向这条记录的上一个版本; - DB_ROW_ID,隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以DB_ROW_ID产生一个聚簇索引。 ![](//img1.jcloudcs.com/developer.jdcloud.com/2c16aee6-8c93-4fec-b2d2-43235b202fc020220919113959.png) #### 2.2 undo日志 undo log 主要有两种,insert undo log和update undo log。insert undo log代表事务在 insert 新记录时产生的 undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃。 update undo log事务在进行 update 或 delete 时产生的 undo log ; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被 purge 线程统一清除。 #### 2.3 Read View Read View 是事务进行快照读操作的时候生产的读视图。在该事务执行快照读的那一刻,会生成数据库系统当前的一个读视图,记录并维护系统当前活跃事务的 ID。在数据库中,当开启一个事务时,会被分配一个ID,依次递增,所以最新的事务,ID最大。包含的内容后续有详细说明。 ![](//img1.jcloudcs.com/developer.jdcloud.com/094ae67c-5253-43e3-8685-896a57cf11f320220919114025.png) #### 2.4 当前读和快照读 undo 日志和Read View中提到的快照读是数据库记录的读取方式,是相较于当前读的另一种读取方式。 当前读,读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。 快照读,不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,它的实现是基于多版本并发控制,读到的并不一定是数据的最新版本,有可能是之前的历史版本。 ### 3 MVCC 的实现原理 当一个修改记录的事务提交后,会将修改前的记录写入update undo log并且使用当前记录的回滚指针指向它。示例如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/c08bc8e3-9c0d-4541-a7f5-a56ceb626a4a20220919114047.png) 当后续再有事务修改该记录时,会同样将当前记录写入update undo log,当前记录的回滚指针指向它,undo log中就会存储着之前的记录形成的记录链表。 ![](//img1.jcloudcs.com/developer.jdcloud.com/932acf38-f381-411e-b82a-a28b23b34b1620220919114057.png) 当有事务进行快照读操作读取记录时,会生成读视图。这个读视图会生成数据库系统当前的一个快照,记录并维护当前活跃事务的ID,主要包含三部分内容,survival_id_list,当前正在活跃的事务ID列表;smart_id,当前活跃事务ID的最小值;max_id,已出现过的事务ID值加1。此处这三个内容的名称是自己定义的,便于理解。 当需要确定对于当前事务,某个表的某条记录哪个版本可见时,首先会获取当前记录的事务ID,记为DB_TRX_ID。 然后会根据下面的比较方式与当前事务的读视图比较,确定哪个版本的记录可见。 如果DB_TRX_ID < smart_id时,该记录对当前事务可见。否则如果DB_TRX_ID >= max_id,该记录对当前事务不可见。否则如果survival_id_list包含DB_TRX_ID,该记录对当前事务不可见。否则如果survival_id_list不包含DB_TRX_ID,该记录对当前事务可见。 当确定当前记录可见,返回当前记录结果,否则根据当前记录的回滚指针,获取上一条历史记录的信息,取其DB_TRX_ID,继续上述的可见性判断。可见返回,不可见继续往前。重复上述步骤,直到获取到对当前事务可见的记录。 ![](//img1.jcloudcs.com/developer.jdcloud.com/028f9f0c-6441-4906-986a-53147b718bfa20220919114113.png) 对于上述表格中的场景,在 可重复读级别下,事务50的读视图信息为survival_id_list=[10,20,50,15], smart_id=10, max_id=51。根据上述的可见性判断事务30对于读视图是可见的,所以查询到的name为‘li30’,虽然后面的两次查询时有事务10、20的修改提交,但由于使用的是刚开始的读视图,事务10、20对于该视图不可见,所以3次的查询结果都是‘li30’。 事务15的读视图信息为survival_id_list=[20,50,15], smart_id=10, max_id=51。根据上述的可见性判断事务10对于读视图是可见的,所以查询到的name为‘li10’。虽然后面一次查询时有事务20提交,但对于当前读视图不可见,所以两次的查询结果都是‘li10’。 ### 4 总结 MySQL通过上述的MVCC机制可以做到,在并发读写数据库时,读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。在不可重复读的隔离级别下,是每个快照读都会生成并获取最新的读视图;而在 可重复读隔离级别下,则是同一个事务中的第一个快照读才会创建读视图, 之后的快照读获取的都是同一个读视图。 ------------ ###### 自猿其说Tech-JDL京东物流技术与数据智能部 ###### 作者:管碧强
原创文章,需联系作者,授权转载
上一篇:Dive into TensorFlow系列(2)- 解析TF核心抽象op算子
下一篇:京东小程序折叠屏适配探索
相关文章
【技术干货】企业级扫描平台EOS关于JS扫描落地与实践!
突破容量极限:TiDB 的海量数据“无感扩容”秘籍
京东智联云MySQL数据库如何保障数据的可靠性?
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号