MVCC机制的原理

一 使用场景

首先要明确,MVCC机制针对的场景主要是读-写并发。因为读-读并发不会产生问题,写-写并发通过加锁实现,读-写并发场景下会产生诸如脏读、不可重复读、幻读等问题。

二 MVCC依赖的数据结构

1 undolog

作为回滚使用的重要文件,mysql每次更新数据之前,都会先写undolog。也就是说,每条数据的每次操作,都会形成一条undolog数据,这些数据根据时间关系就形成了一条链表,链表中的每个节点即是一个快照。MVCC即是为每个事务寻找对应的快照(快照读)。

2 数据表的三个隐藏字段

mysql表中每行数据都有三个隐藏的重要字段,DB_TRX_ID(最近一次被哪个事务更新)、DB_ROW_ID(隐含的主键id,如果未指定主键,会用该列创建主键索引)、DB_ROLL_PT(回滚指针,指向上个版本的数据,一条数据通过该指针形成链表)。

3 readView

每创建一个事务的时候,就会随事务创建对应的readView视图。readView中包含以下数据结构:

  • 当前事务id(Transaction ID
  • 当前所有未提交的事务集合(m_ids
  • 创建readView时最小的事务id(min_trx_id
  • 创建readView时最大的事务id(max_trx_id

顺便说一下,在RC隔离级别下,事务中每次select操作都会重新创建一个readView;而在RR隔离级别下,只会在第一次select时创建readView。这也就解释了为什么RC级别下可以解决脏读、RR级别下可以解决不可重复读的问题。

三 快照读

基于上述的数据结构,MVCC为每个事务的select操作找到对应的数据版本。具体的:

先用undolog中最新的数据比较,

DB_TRX_ID < min_trx_id:说明当前版本的数据提交早于readview中所有的事务,因此该版本数据是可见的。

DB_TRX_ID > max_trx_id:说明当前版本的数据提交晚于readview中所有的事务,因此该版本数据是不可见的。

DB_TRX_ID在min_trx_id和max_trx_id之间,并且在集合m_ids中:说明在创建readView时该版本还未提交,在创建后提交了,因此也是不可见的。

DB_TRX_ID在min_trx_id和max_trx_id之间,并且不在集合m_ids中:说明在创建readView时该版本已经提交了,因此是可见的。

经历以上比较,如果数据不可见,那么就顺着undolog的链表,取上一个版本的数据,用上个版本的DB_TRX_ID重新执行上述比较流程,直到找到可见的版本数据。

另外补充一下快照读当前读的区别,快照读的概念仅存在于RC和RR隔离级别下。其实我们常用的select操作都是快照读,当前读一般是加锁读操作或者是修改操作,比如select ... for update, insert,delete,update...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值