一、名词解释
- m_ids:当前所有活跃事务,当前所有未提交的事务
- 版本链:记录修改过程中形成的版本链表,包含undolog日志和数据缓存页
二、版本链
开启事务 100 | 开启事务 300 |
---|---|
insert into t_user(id, name) values(1, ‘张三’); | update t_user set name=‘李四’ where id = 1; |
commit; | update t_user set name=‘王五’ where id = 1; |
上述操作会生成如下版本链
三、各个隔离级别数据读取
- Read Uncommited 直接读取版本链第一条数据
- Serializable 加锁方式读取
- Read Commit 使用mvcc
- Repeat Read 使用mvcc
四、MVCC可见版本分析过程
- 获取readView,主要包含活跃事务列表m-ids
- 从上向下,依次用每个版本链中事务trx_id与活跃事务列表trx_id比较,获取到版本链中符合规则的记录为当前可见记录
五、规则
- 如果trx_id大于活跃事务列表m_idx中的最大值,说明该事务在生成readView后,所以记录不可见
- 如果trx_id值在m_idx最大最小值中间,就要判断是否包含,如果包含说明事务未提交,不可见;如果不包含,说明生成readView时该版本已经提交,所以可见
- 如果trx_id小于m_idx最小值,说明生成readView时该版本已经提交,所以可见
六、Read Commit与Repeat Read区别
- RC隔离级别下,每次读取生成一个readView
- RR隔离级别下,事务开启时生成readView
七、Repeat Read示例
假设目前有事务id为300,400和500在运行
执行过程和结果
序号 | 事务 300 更新数据 | 事务 600 读取数据 | 读取结果 |
---|---|---|---|
1 | update t_user set name=‘李四’ where id=1; | ||
2 | update t_user set name=‘王五’ where id=1; | ||
3 | select name from t_user where id=1; | 张三 | |
4 | commit; | ||
5 | select name from t_user where id=1; | 张三 |
版本链如图:
读取分析:
- 事务600开始读操作时生成readView,m_idx包含[300,400,500]
- 在执行到第3行时,依次根据规则判断版本链中trx_id与m_idx关系,定位可见 - trx_id:100,即张三那条记录
- 在执行到第5行时,readView中m_idx依然包含的是[300,400,500],分析结果不变
END