基于Undo Log版本链快照读原理

1、抛砖引玉问题:
(1)什么是Undo Log?
作用1-回滚日志:每次事务在执行DML语句,便会将相反的DML写入undo log,等到事务RollBack时使数据恢复到事务最开始状态(原子性操作);

作用2-非锁定一致性读:当前事务读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取,实现原理:

采用“链”的方式保存数据变化,这个多版本就是通过“链”来遍历访问的

(2)版本链是如何组织的?
TRX_ID:行记录产生时的事务ID
DB_ROLL_PTR:指向行记录变更前的数据行版本


Undo Log版本链.png

2、关于undo log版本链何时删除的问题?
(1)undo log不是会被删除吗?
(2)中间数据被删除了,版本链会被破坏?
答:MySQL InnDO引擎确保版本链数据“不在被引用”后再删除,官网是说法时,一致性读保证数据一致性时候,没有别的并行事务引用的时候再删除。

3、版本链到底是如何运行机制保证数据一致性读的呢?这里需要引出一个新的概念:
(1)快照读:最普通的SELECT查询语句;
(2)快照读:insert、update、delete、select ... for update、select ... lock in share mode;
(3) ReadView:快照读SQL执行时,MVCC提取数据的依据;
注意:是快照读时,才使用MVCC提取数据,当前读时,使用Next-Key Lock(行锁+间隙锁);

4、ReadView概念说明,ReadView是一个数据结构,包含4个字段:
(1)m_ids:当前活跃的事务编号集合
(2)min_trx_id:最小活跃事务编号
(3)max_trx_id:预分配事务编号(当前最大事务编号N+1)
(4)creator_trx_id:ReadView创建者的事务编号

读已提交(RC):在每一次快照读时候生成一个ReadView


RC隔离级别下ReadView.png

可重复读(RR):在每一次快照读时候生成一个ReadView

5、版本链数据访问规则:
(1)判断当前事务id是否等于creator_id,如果等于说明数据就是自己这个事务更改的,可以访问
(2)判断trx_id < min_trx_id?成立说明数据已提交,可以访问;
(3)判断trx_id > max_trx_id? 成立说明该事务在ReadView生成以后才开启,不允许访问;
(4)判断 min_trx_id < trx_id <= max_trx_id ? ,成立则在m_ids中对比,不存在说明事务已提交,可以访问;

6、按照以上访问规则由上而下进行版本链的数据判断

第一次快照读(RC、RR):

(1)判断数据版本 (trx_id=3)= creator_id(4)?成立说明数据就是自己这个事务修改的,可以访问;-- 显然这里不成立,即:事务C结果无法访问;

(2)判断当前事务id(trx_id=3)< min_trx_id=2 ?成立说明数据已提交,可以访问;-- 显然这里不成立,即:trx_id=2行不可访问;

(3)判断当前事务id(trx_id=3)> max_trx_id=5? 成立说明该事务在ReadView生成以后才开启,不允许访问; -- 显然这里不成立

(4)判断 min_trx_id=2 < =(trx_id=3) <= max_trx_id=5 ? ,成立则在m_ids中对比,不存在说明事务已提交,可以访问; -- 这里trx_id在m_ids内,显然未提交

在RC模式下,trx_id为2和3都是活跃事务id(在m_ids集合内),显然无法访问,只有trx_id=1 < min_trx_id,说明已提交,可访问;

第二次快照读(RC):
(1)trx_id=3,在活跃id中且不小于最小事务id(min_trx_id),所以不可访问;
(2)trx_id=2,满足min_trx_id=2 < =(trx_id=2) <= max_trx_id=5 ,且不在活跃id集合(m_ids)中,所以可以访问;

第二次快照读(RR):始终是第一次快照读的结果一致,只是第一次ReadView的复用;

所以RR隔离级别解决了不可重复读的问题;

7、RR隔离级别使用MVCC可以解决幻读的问题吗?
答:
能:连续多次快照读,ReadView会产生复用,无幻读问题;

但不是完全解决:两次ReadView之间产生“当前读”,当前读会产生新的ReadView,导致产生幻读;

你可能感兴趣的:(基于Undo Log版本链快照读原理)