MySQL——MVCC多版本并发控制

1. innoDB的主要日志介绍

binlog:服务层生产日志,数据恢复、数据库复制

redo log:数据在物理层面的修改,断电恢复、保证一致性和持久性,顺序 :写入数据->redo log buffer->file system buffer->fsync操作->redo log file ->commit

undo log:事务回滚、实现MVCC

2. innoDB MVCC

2.1 隐含字段

6-byte DB_TRX_ID:最新更新这行记录的事务ID,每处理一个事务,其值自动+1

7-byte DB_ROLL_PTR:指向rollback segment 的undo log记录的指针

6-byte DB_ROW_ID(若没有设置主键MySQL则隐式的创建一个主键,因为InnoDB会自动创建一个主键索引,所以必须要一个主键)

DELETE BIT位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候

2.2 实现原理

innodb MVCC主要是为Repeatable-Read事务隔离级别做的。在此隔离级别下,A、B客户端所示的数据相互隔离,互相更新不可见

了解innodb的行结构、Read-View的结构对于理解innodb mvcc的实现有重要意义

当事务更改该行的值时,会进行如下操作:

用排他锁锁定该行

记录redo log

把该行修改前的值Copy到undo log,即上图中下面的行

修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行

若回滚,根据回滚指针从undo log找出事务修改前的版本并恢复。

若提交,更改事务状态为COMMIT,其他什么都不做(见下面的具体操作)

靠 readView (事务视图) 来实现的。多个 readView 组成 undo log(回滚日志)。

innoDB的mvcc主要是为了Repeatable-Read隔离级别实现的。

2.3 具体操作执行过程

begin->用排他锁锁定该行->记录redo log->记录undo log->修改当前行的值,写事务编号,回滚指针指向undo log中的修改前的行

上述过程确切地说是描述了UPDATE的事务过程,其实undo log分insert和update undo log,因为insert时,原始的数据并不存在,所以回滚时把insert undo log丢弃即可,而update undo log则必须遵守上述过程

下面分别以select、delete、 insert、 update语句来说明过程

SELECT

Innodb检查每行数据,确保他们符合两个标准:

1、InnoDB只查找版本早于当前事务版本的数据行(也就是数据行的版本必须小于等于事务的版本),这确保当前事务读取的行都是事务之前已经存在的,或者是由当前事务创建或修改的行

2、行的删除操作的版本一定是未定义的或者大于当前事务的版本号,确定了当前事务开始之前,行没有被删除

符合了以上两点则返回查询结果。

INSERT

InnoDB为每个新增行记录当前系统版本号作为创建ID。

DELETE

InnoDB为每个删除行的记录当前系统版本号作为行的删除ID。

UPDATE

InnoDB复制了一行。这个新行的版本号使用了系统版本号。它也把系统版本号作为了删除行的版本。

说明

insert操作时 “创建时间”=DB_ROW_ID,这时,“删除时间 ”是未定义的;

update时,复制新增行的“创建时间”=DB_ROW_ID,删除时间未定义,旧数据行“创建时间”不变,删除时间=该事务的DB_ROW_ID;

delete操作,相应数据行的“创建时间”不变,删除时间=该事务的DB_ROW_ID;

select操作对两者都不修改,只读相应的数据


3. ReadView

MVCC 中维护了一个 ReadView 结构,主要包含了当前系统未提交的事务列表 TRX_IDs(事务ID) {TRX_ID_1, TRX_ID_2, ...},还有该列表的最小值 TRX_ID_MIN 和 最大值TRX_ID_MAX。

在进行 SELECT 操作时,根据数据行快照的 TRX_ID 与 TRX_ID_MIN 和 TRX_ID_MAX 之间的关系,从而判断数据行快照是否可以使用:

TRX_ID < TRX_ID_MIN,表示该数据行快照时在当前所有未提交事务之前进行更改的,因此可以使用。

TRX_ID > TRX_ID_MAX,表示该数据行快照是在事务启动之后被更改的,因此不可使用。

TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX,需要根据隔离级别再进行判断:

提交读:如果要读取的数据还存在于TRX_ID事务列表中,表示该数据行快照对应的事务还未提交,则该快照不可使用。否则表示已经提交,可以使用。

可重复读:都不可以使用。因为如果可以使用的话,那么其它事务也可以读到这个数据行快照并进行修改,那么当前事务再去读这个数据行得到的值就会发生改变,也就是出现了不可重复读问题。

可重复读隔离级别则在第一次读的时候会生成一个ReadView,之后的读都复用之前的ReadView。(会通过ROLL_PTR去查询初始的数据行结果,来保证数据相同)

你可能感兴趣的:(MySQL——MVCC多版本并发控制)