MySQL之MVCC机制:为什么你改了的数据我还看不见?

本文深入探讨了MySQL中的MVCC(多版本并发控制)机制,旨在解决并发事务中的读写冲突。分析了并发事务的四种场景:读-读、写-写、读-写和写-读,以及针对这些场景的解决方案。重点讲解了MVCC在InnoDB引擎中的实现,包括隐藏字段、Undo-log日志和ReadView的作用,以及它们如何协同工作以实现非阻塞的读操作和防止脏读、不可重复读及幻读问题。文章还对比了RC和RR级别下MVCC的不同之处,揭示了MVCC在提高数据库并发性能上的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、并发事务的四种场景

并发事务中又会分为四种情况,分别是读-读、写-写、读-写、写-读,这四种情况分别对应并发事务执行时的四种场景,为了后续分析MVCC机制时方便理解,因此先将这几种情况说明,咱们首先来看看读-读场景。

1.1、读一读场景

读-读场景即是指多个事务/线程在一起读取一个相同的数据,比如事务T1正在读取ID=88的行记录,事务T2也在读取这条记录,两个事务之间是并发执行的。

广为人知的一点:MySQL执行查询语句,绝对不会对引起数据的任何变化,因此对于这种情况而言,不需要做任何操作,因为不改变数据就不会引起任何并发问题。

1.2、写-写场景

写-写场景也比较简单,也就是指多个事务之间一起对同一数据进行写操作,比如事务T1对ID=88的行记录做修改操作,事务T2则对这条数据做删除操作,事务T1提交事务后想查询看一下,哦豁,结果连这条数据都不见了,这也是所谓的脏写问题,也被称为更新覆盖问题,对于这个问题在所有数据库、所有隔离级别中都是零容忍的存在,最低的隔离级别也要解决这个问题。

1.3、读-写、写-读场景

读-写、写-读实际上从宏观角度来看,可以理解成同一种类型的操作,但从微观角度而言则是两种不同的情况,读-写是指一个事务先开始读,然后另一个事务则过来执行写操作,写-读则相反,主要是读、写发生的前后顺序的区别。

并发事务中同时存在读、写两类操作时,这是最容易出问题的场景,脏读、不可重复读、幻读都出自于这种场景中,当有一个事务在做写操作时,读的事务中就有可能出现这一系列问题,因此数据库才会引入各种机制解决。

1.4、各场景下解决问题的方案

在《MySQL锁机制》中,对于写-写、读-写、写-读这三类场景,都是利用加锁的方案确保线程安全,但上面说到过,加锁会导致部分事务串行化,因此效率会下降,而MVCC机制的诞生则解决了这个问题。

先来设想一个问题:加锁的目的是什么?防止脏写、脏读、不可重复读及幻读这类问题出现。

对于脏写问题,这是写-写场景下会出现的,写-写场景必须要加锁才能保障安全,因此先将该场景排除在外。再想想:对于读-写并存的场景中,脏读、不可重复读及幻读问题都出自该场景中,但实际项目中,出现这些问题的几率本身就比较小,为了防止一些小概念事件,就将所有操纵同一数据的并发读写事务串行化,这似乎有些不讲道理呀,就好比:

为了防止自家保险柜中的3.25元被偷,所以每天从早到晚一直守着保险柜,这合理吗?并不合理,毕竟只有千日做贼,那有千日防贼的道理。

因此MySQL就基于读-写并存的场景,推出了MVCC机制,在线程安全问题和加锁串行化之间做了一定取舍,让两者之间达到了很好的平衡,即防止了脏读、不可重复读及幻读问题的出现,又无需对并发读-写事务加锁处理。

咋做到的呢?接下来一起来好好聊一聊大名鼎鼎的MVCC机制。

二、MySQL-MVCC机制综述

MVCC机制的全称为Multi-Version Concurrency Control,即多版本并发控制技术,主要是为了提升数据库并发性能而设计的,其中采用更好的方式处理了读-写并发冲突,做到即使有读写冲突时,也可以不加锁解决,从而确保了任何时刻的读操作都是非阻塞的。

但与其说是MySQL-MVCC机制,还不如说是InnoDB-MVCC机制,因为在MySQL众多的开源存储引擎中,几乎只有InnoDB实现了MVCC机制,类似于MyISAM、Memory等引擎中都未曾实现,那其他引擎为何不实现呢?不是不想,而是做不到,这跟MVCC机制的实现原理有关,这点放在后续详细讲解~

不过为了更好的理解啥叫MVCC多版本并发控制,先来看一个日常生活的例子~

2.1、MVCC技术在日常生活中的体现

不知道各位小伙伴中,是否有人做过论坛这类业务的项目,或者类似审核的业务需求,以掘金的文章为例,此时来思考一个场景:

假设我发布了一篇关于《MySQL事务机制》的文章,发布后挺受欢迎的,因此有不少小伙伴在看,其中有一位小伙伴比较细心,文中存在两三个错别字,被这位小伙伴指出来了,因此我去修正错别字后重新发布。

问题来了,对于文章首次发布也好,重新发布也罢,绝对要等审核通过后才会正式发布的,那我修正文章后重新发布,文章又会进入「审核中」这个状态,此时对于其他正在看、准备看的小伙伴来说,文章是不是就不见了?毕竟文章还在审核撒,因此对这个业务需求又该如何实现呢?多版本!

啥意思呢?也就是说,对于首次发布后通过审核的文章,在后续重新发布审核时,用户可以看到更新前的文章,也就是看到老版本的文章,当更新后的文章审核通过后,再使用新版本的文章代替老版本的文章即可。

这样就能做到新老版本的兼容,也能够确保文章修正时,其他正在阅读的小伙伴不会受影响,而MySQL-MVCC机制的思想也大致相同。

2.2、MySQL-MVCC多版本并发控制

MySQL中的多版本并发控制,也和上面给出的例子类似,毕竟回想一下,脏读、不可重复读、幻读问题都是由于多个事务并发读写导致的,但这些问题都是基于最新版本的数据并发操作才会出现,那如果读、写的事务操作的不是同一个版本呢?比如写操作走新版本,读操作走老版本,这样是不是无论执行写操作的事务干了啥,都不会影响读的事务?答案是Yes。

不过要稍微记住,MySQL中仅在RC读已提交级别、RR不可重复读级别才会使用MVCC机制,Why?

因为如果是RU读未提交级别,既然都允许存在脏读问题、允许一个事务读取另一个事务未提交的数据,那自然可以直接读最新版本的数据,因此无需MVCC介入。

同时如若是Serializable串行化级别,因为会将所有的并发事务串行化处理,也就是不论事务是读操作,疑惑是写操作,都会被排好队一个个执行,这都不存在所谓的多线程并发问

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值