简单研究了一下MVCC

234 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

什么是MVCC?

MVCC(Multi-Version Concurrency Control)多版本并发控制机制,就是这个机制可以让我们在可重复读隔离级别下不同事务不必加锁来对数据进行隔离,来实现数据的可见与不可见。

MVCC实现

MVCC主要是通过undo日志版本链与read view 来实现的。 事务id生成规则:我们对数据的任何第一次修改操作(insert,update,delete),注意并不是 begin 或 start transaction命令。

undo日志版本链

我们对数据的任何修改操作(insert,update,delete)都会通过日志的方式,类似“砌墙”的方式以条一条记录下来。每条记录都有2个隐藏字段(trx_id,roll_pointer)来将一条条记录进行串联。

示例

1.mysql现有数据如下: image.png

2.开启多个事务来介绍undo日志版本链

纵向代表不同事务,横向代表时间顺序上不同事务的操作(注:正常情况下,事务id都是连续的,我这里仅仅是演示)。

image.png

3.undo版本链 image.png

read view视图

在读已提交或者可重复读隔离级别下当执行查询操作(select),会基于目前所有事务id形成一个数据集(视图),从而将事务划分为三个区间(已提交事务,未提交事务或提交事务,未来事务),这个数据集一旦形成在事务结束前是不会改变的(如果是读已提交事务隔离级别,则每次查询都会生成新的数据集)。

数据集视图由2部分组成

  • 未提交的所有事务id组成的数组(最小的那个未提交事务id被称为min_id)
  • 已创建的最大事务id(max_id)

针对上述示例当事务300进行查询时,生成的数据集为:(100,300),300 image.png

查找的时候undo日志版本链从上向下根据trx_id规则进行比对,满足条件则可见,不满足则不可见。(示例查询undo日志版本链最新一条记录的trx_id为300,根据如下规则判断满足3-a条件所以可见money=200。注:如果第一条记录的trx_id根据规则不可见则会找下一条trx_id进行比对,直到找到满足条件的记录)

  1. 如果 row 的 trx_id 落在蓝色部分(trx_id<min_id),表示这个数据是已提交的事务,可见。
  2. 如果 row 的 trx_id 落在黄色部分(trx_id>max_id ),表示这个版本是由将来启动的事务生成的,是不可见的(若 row 的 trx_id 就是当前自己的事务是可见的。
  3. 如果 row 的 trx_id 落在橘色部分(min_id <=trx_id<= max_id),那就包括两种情况 a. 若 row 的 trx_id 在未提交事务数组中,表示这个版本是由还没提交的事务生成的,不可见(若 row 的 trx_id 就是当前自己的事务是可见的); b. 若 row 的 trx_id 不在未提交事务数组中,表示这个版本是已经提交了的事务生成的,可见。

InnoDb引擎在Mysql下如何工作?

image.png

  • Undo日志:当事务回滚时,用来更新Buffer Pool里面的数据。
  • Redo日志:如果事务提交但Buffer Pool中数据还未刷盘,则通过该日志文件恢复Buffer Pool中数据。
  • BinLog日志:恢复磁盘中数据或者数据库之间同步数据。

为什么要设计Buffer Pool?

为了性能。如果所有数据操作都要进行磁盘io随机读写,性能消耗太大。

binlog为什么要向redo日志写commit标识?

该动作标志了事务的完成,是为了保证事务提交后二者数据保持一致。

redo日志可以顺序写,为什么磁盘文件不可以?

因为redo日志没有删除动作,但是mysql的数据有删除动作。