赞
踩
class ReadView { // 省略... private: /** 高水位,大于等于这个ID的事务均不可见*/ trx_id_t m_low_limit_id /** 低水位:小于这个ID的事务均可见 */ trx_id_t m_up_limit_id; /** 创建该 Read View 的事务ID*/ trx_id_t m_creator_trx_id; /** 创建视图时的活跃事务id列表*/ ids_t m_ids; /** 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG, * 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG*/ trx_id_t m_low_limit_no; /** 标记视图是否被关闭*/ bool m_closed; // 省略... }; m_ids; // 一张列表,用来维护Read View生成时刻,系统正活跃的事务ID up_limit_id; // 记录m_ids列表中事务ID最小的ID(没有写错) low_limit_id; // ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1 creator_trx_id // 创建该ReadView的事务ID
在实际读取数据版本链的时候,是能读取到每一个版本对应的事务ID的,即:当前记录的DB_TRX_ID
那么,现在手里面有的东西就有,当前快照读的 ReadView 和 版本链中的某一个记录的DB_TRX_ID
所以现在的问题就是,当前快照读,应不应该读到当前版本记录?
对应源码策略
如果查到不应该看到当前版本,接下来就是遍历下一个版本,直到符合条件,才可以看到
下面的 readview 是当你进行select的时候,会自动形成
假设当前有条记录:
name | age | **DB_TRX_ID(**创建该记录的事务ID) | **DB_ROW_ID(**隐式主键) | **DB_ROLL_PTR(**回滚指针) |
---|---|---|---|---|
张三 | 28 | null | 1 | null |
事务操作:
事务4:修改name(张三)变成name(李四)
// 事务2的 Read View
m_ids; // 1,3
up_limit_id; // 1
low_limit_id; // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID
creator_trx_id // 2
此时版本链是:
只有事务4修改过该行记录,并在事务2执行快照读前,就提交了事务
事务2在快照读该行记录的时候,就会拿该行记录的 DB_TRX_ID 去跟 up_limit_id,low_limit_id和活跃事务ID列表(trx_list)进行比较,判断当前事务2能看到该记录的版本
// 事务2的 Read View m_ids; // 1,3 up_limit_id; // 1 low_limit_id; // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务ID creator_trx_id // 2 // 事务4提交的记录对应的事务ID DB_TRX_ID=4 // 比较步骤 DB_TRX_ID(4)< up_limit_id(1) ? 不小于,下一步 DB_TRX_ID(4)>= low_limit_id(5) ? 不大于,下一步 m_ids.contains(DB_TRX_ID) ? 不包含,说明,事务4不在当前的活跃事务中 // 结论 故,事务4的更改,应该看到 所以事务2能读到的最新数据记录是事务4所提交的版本,而事务4提交的版本也是全局角度上最新的版本
select * from user lock in share mode;
以加共享锁方式进行读取,对应的就是当前读
测试表
--设置RR模式下测试 mysql> set global transaction isolation level REPEATABLE READ; --重启终端 mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ --依旧用之前的表 create table if not exists account( id int primary key, name varchar(50) not null default '', blance decimal(10,2) not null default 0.0 )ENGINE=InnoDB DEFAULT CHARSET=UTF8; --插入一条记录,用来测试 mysql> insert into user (id, age, name) values (1, 15,'黄蓉');
测试用例1-表1:
测试用例2-表2:
用例1与用例2:唯一区别仅仅是 表1 的事务B在事务A修改age前快照读过一次age数据,而 表2 的事务B在事务A修改age前没有进行过快照读
结论:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。