Mysql实现可重复读的方式——MVCC
目录
简介
MVCC:(Multi-Version Concurrency Control)多版本并发控制
隐式字段
Mysql每一行数据都有几个隐藏的字段,用于标记本条数据的历史版本信息以及事务信息等。
DB_TRX_ID:最近修改(修改/插入)事务ID,记录创建这条记录/最后一次修改该记录的事务ID
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本
DB_ROW_ID:隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了
undo日志版本链
Mysql在执行一条条SQL语句的时候,对每一条数据的历史记录都会进行记录,采用的方式就是undo日志版本链。
例:
如下数据:
表:balance
id name account
1 lilei 3000
分别执行如下三条数据:
DB_TRX_ID(事务ID):100
update balance set name = lilei2 where id = 1;
commit;
DB_TRX_ID(事务ID):200
update balance set name = lilei3 where id = 1;
commit;
DB_TRX_ID(事务ID):300
update balance set name = lilei4 where id = 1;
commit;
则版本链信息如下:
read-view一致性视图
当一个select语句查询开始的时候,会生成当前事务的read-view一致性视图,视图规则为:所有未提交的事务ID组成的数组与已提交的最大的事务ID,格式如下:
[100,200],300
当其他事务对数据进行修改的时候,本事务的read-view一致性视图不会变化,保证了可重复读机制。
MVCC比对规则
1. 当前事务ID小于read-view中的最小事务ID,则本事务一定是已经提交过了的,可见。
2. 当前事务ID如果大于read-view中的最大事务ID,则本事务是在当前事务开始后新建的,不可见。
3. 当前事务ID小于等于read-view中的最大事务ID且大于等于read-view中的最小事务ID,分两种情况:
3.1 如果当前事务ID在数组中,则数据是由未提交得事务更新得,除事务本身以外,其他事务不可见
3.2 如果当前事务ID不在数组中,则数据是由已提交得事务更新得,可见。
实例
# Transaction 100 | # Transaction 200 | # Transaction 300 | # select 1 | # select 2 |
begin; | begin; | begin; | begin; | begin; |
update test set c1 = '123' where id =1; | ||||
update test set c1 = '666' where id =5; | ||||
update account set name = 'lilei300' where id = 1; | ||||
commit; | ||||
select name from account where id = 1; read-view:[100,200],300 结果为:lilei300 | ||||
update account set name = 'lilei1' where id = 1; | ||||
update account set name = 'lilei2' where id = 1; | ||||
select name from account where id = 1; read-view:[100,200],300 结果为:lilei300 | ||||
commit; | ||||
update account set name = 'lilei3' where id = 1; | ||||
update account set name = 'lilei4' where id = 1; | ||||
select name from account where id = 1; read-view:[100,200],300 结果为:lilei300 | select name from account where id = 1; readview:[200], 300 结果为:lilei2 | |||
commit; |