快照在MVCC里是怎么工作的?

本文深入探讨了数据库事务中的可重复读实现机制,重点介绍了多版本并发控制(MVCC)如何维护快照视图。在MVCC中,每个事务都有不同的数据版本,通过事务ID控制可见性。事务开始时记录活跃事务ID,用于判断数据版本是否可见。在可重复读隔离级别下,写操作通过先读后写确保一致性,同时利用锁机制防止数据冲突。此外,还讨论了当前读与快照读的区别以及加锁策略对读写一致性的影响。

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

1、可重复读是怎么实现的?

这是一道高频面试题,大多数人接触这个问题时都会被告知是在事务开始时,基于当前数据创建了一个临时视图,后面的读操作都是在这个视图上进行的。但这只是个笼统的说法或者说一个形象的比喻,没有涉及到视图的存在方式和实现原理,是应付不了面试官的。

想要回答这个问题,就必须了解MVCC的工作机制

2、MVCC维护快照视图的方法
(1)视图的逻辑存在模型
  • MVCC又叫多版本控制机制,顾名思义,它是用来控制多个版本的数据的。
  • 在MVCC的模型中,每一行数据都是有不同的版本的,事务在进行查询会选择对当前事务可见的数据版本,这些可见的数据版本共同组成了视图。那么,数据版本是怎么控制的呢?
(2)数据版本的控制方式
  • 实际上是通过事务的ID来控制的,每个事务开始时,都会跟系统申请一个id,叫做transaction id。这个id是严格递增的,确保不会重复。
  • 当事务对一行记录进行修改时,就会生成一条新的版本记录,并将事务的transaction id作为该记录的版本号。

那么旧的版本记录去哪里了呢?

(3)数据版本的实际存在方式
  • 事实上,旧的版本记录不是直接以物理形式存在的,它是通过undo log(回滚日志)与最新的记录版本运算得出的。事务查询时,若记录的最新版本对当前事务不可见,就会进行运算回滚,然后检查回滚后的记录版本对当前事务是否可见,不可见则回滚到可见为止。

那么事务是如何判断数据版本对自己是否可见呢?

3、MVCC的可见版本判断方法

在事务开始时,MVCC会生成一个数组,用于记录当前系统中活跃的事务ID,所谓活跃,即已经开始但未提交的事务。数组中的最小版本号称之为低水位, 最大版本号 + 1称之为高水位。而判断数据版本是否可见就是根据这三个数据来进行的

  • 若数据版本号小于低水位,低水位是本事务开始时未提交事务中id最小的事务,在此之前的事务必定已经提交,说明该数据版本是在本事务开始前已经提交的,对本事务可见
  • 若数据版本号大于或等于高水位,则说明该数据版本是晚于本事务开始的事务生成的,对本事务不可见
  • 若数据版本号介于低水位和高水位之间,那么则有两种情况
  1. 若该数据版本号位于数组中,则说明该数据在本事务开始前还未提交,不可见
  2. 若该数据版本号不在数组中,那么说明该数据时在本事务开始前提交的,可见
  • 若数据版本号是本事务,那么当然是可见的。

前文提到了事务开始概念,如果使用的是begin/start transaction开启的事务,那么事务开始时机是在第一次select(快照读)之后,而采用start transaction with consistent snapshot则会立即开启事务。

而在RC(提交读)的隔离级别下,就是通过操作前重新生成新视图,也就是不断更新高低水位和活跃数组来实现提交读的

4、写同步问题

前文提到在RR(可重复读)级别对未提交的数据版本不可见,那么倘若事务需要修改记录,就有可能不是在最新版本的基础上进行修改,那么其他事务的修改不就失效了吗?
实际上,在涉及到修改操作时,MySQL是先读再写,这个读不同于之前的快照读,而是获取最新版本数据的当前读。进行当前读需要对记录加上写锁,写锁是一个互斥锁,持有锁的事务在提交前都不会释放锁,后续申请锁的事务会陷入阻塞,以此来保证写操作的一致性

除了进行写操作,也可以通过以下方式对记录加上读锁或写锁进行当前读:

  • select … from … lock in share mode;
  • select … from … for update;
    前者是加上读锁,读锁可共享,如果加锁的记录只有读锁则可以获取到最新已提交的数据版本,但如果加读锁的记录上有写锁,则会阻塞;
    后者是加上写锁,只有在加锁记录没有读写锁的情况下才能加锁成功,会获取到已提交的最新数据版本。记录被加上写锁时,其他事务的当前读(加读锁或写锁读)都会被阻塞。

也就是说,可重复读是在快照读的维度上进行实现的。对于当前读,需要获取到最新的版本数据,会绕开版本控制,已经不在可重复读的范畴内了
如果换一个角度思考,当前事务在进行当前读时会进行加锁,加锁成功后其他事务无法进行修改,多次当前读的结果也是一样的,也算是一种可重复读吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值