IT评测·应用市场-qidao123.com
标题:
[MySQL][深入明白隔离性][下][Read View]具体讲解
[打印本页]
作者:
愛在花開的季節
时间:
2024-7-26 11:01
标题:
[MySQL][深入明白隔离性][下][Read View]具体讲解
1.Read View
1.是什么?
Read View就是事务进行
快照读
操纵的时候生产的
读视图(Read View)
,在该事务执行快照读的那一刻,会天生数据库体系当前的一个快照,记录并维护体系当前活跃事务的ID(当每个事务开启时,都会被分配一个ID,这个ID是递增的,所以最新的事务,ID值越大)
Read View
在 MySQL 源码中,
就是一个类
,
本质是用来进行可见性判定的
即:
当某个事务
执行快照读的时候
,对该记录创建一个 Read View 读视图,把它比作条件,
用来判定当前事务可以或许看到哪个版本的数据
,既可能是当前最新的数据,也有可能是该行记录的 undo log 里面的某个版本的数据
注意:
Read View是事务可见性的一个类,不是事务创建出来的,就会有Read View,而是当这个事务(已经存在),首次进行快照读的时候,MYSQL形成Read View
下面是 ReadView 结构,但为了减少同砚们负担,我们简化一下
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
复制代码
2.明白
在现实读取数据版本链的时候,是能读取到每一个版本对应的事务ID的,即:当前记录的DB_TRX_ID
那么,现在手里面有的东西就有,
当前快照读的 ReadView
和
版本链中的某一个记录的DB_TRX_ID
所以现在的问题就是,当前快照读,应不应该读到当前版本记录?
对应源码策略
如果查到不应该看到当前版本,接下来就是遍历下一个版本,直到符合条件,才可以看到
下面的 readview 是当你进行select的时候,会自动形成
3.整体流程
假设当前有条记录:
name
age
**DB_TRX_ID(**
创建该记录的事务ID)
**DB_ROW_ID(**
隐式主键)
**DB_ROLL_PTR(**
回滚指针)
张三
28
null
1
null
事务操纵:
事务4:修改name(张三)变成name(李四)
当 事务2 对某行数据执行了快照读 ,数据库为该行数据天生一个 Read View 读视图
// 事务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提交的版本也是全局角度上最新的版本
复制代码
2.RR与RC的本质区别
1.当前读和快照读在RR级别下的区别
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前没有进行过快照读
结论:
事务中快照读的结果是非常依靠该事务首次出现快照读的地方
即某个事务中首次出现快照读,决定该事务后续快照读结果的本领
delete同样云云
2.RR与RC的本质区别
正是Read View天生气遇的差别,从而造成RC,RR级别下快照读的结果的差别
在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View
,将当前体系活跃的其他事务记录起来
此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见
即:RR级别下,快照读天生Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
在RC级别下的事务中,每次快照读都会新天生一个快照和Read View
,这就是在RC级别下的事务中可以看到别的事务提交的更新的缘故起因
正是RC每次快照读,都会形成Read View,所以,RC才会有不可重复读问题
总结:
在RC隔离级别下,是每个快照读都会天生并获取最新的Read View
而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4