mysql mvvc
在mysql
中,每一行数据,除了本身的数据,还维护着其他信息,其中包括:
- 一个隐藏
id
, - 事务
id
, - 回滚指针。
其中隐藏id
的选择规则如下:
- 如果有主键
id
, 则是主键id
- 如果有唯一键,则是唯一键
- 如果都没有,则
mysql
生成一个隐藏id
事务id
是顺序递增的,每新增一个事务,事务id
就加1;同时,将(update
|insert
)操作的sql
语句记录在undolog
中,而回滚指针则指向上一个事务的地址。便于当前事务失败的时候,结合undolog
日志,回滚到之前的状态。
但是,当并发的时候,当前事务之前的事务都是历史版本;当存在多个历史版本的时候,我们读的时候要读哪个历史版本呢?这就会设计到一个可见性算法,来计算当前事务读取的是哪一个版本的历史数据。这个可见性算法就是read view
:读视图。
read view
当进行快照读的时候会生成一个事务id
的列表,来保存不同的信息,这个列表就是readview
;通过这些信息来做可见性的判断。这些信息包括:
list
:生成readview
的时候活跃的id
up_limit_id
:当前活跃id
的最小值low_limit_id
:尚未分配的下一个事务id
而readview
在不同的隔离级别下,生成的时机也不同:
- 在
RC
(读已提交隔离级别)下:每次快照读的时候生成新的readview
- 在
RR
(可重复读隔离级别)下:readview
第一次执行快照读的时候会生成,之后都是这个版本的。
其判断规则为:
- 判断被访问版本的
trx_id
属性值是否小于up_limit_id
,如果小于,表明生成该版本的事务在生成ReadView
前已经提交,所以该版本可以被当前事务访问。 - 判断被访问版本的
trx_id
属性值是否大于lower_limit_id
,如果大于,表明生成该版本的事务在生成ReadView
后才生成,所以该版本不可以被当前事务访问。 - 判断被访问版本的
trx_id
属性值是否在list
列表中,如果在,说明创建ReadView
时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView
时生成该版本的事务已经被提交,该版本可以被访问。
例如下方事务列表:
事务1 | 事务2 | 事务3 | 事务4 |
---|---|---|---|
begin | begin | begin | begin |
nothing todo | nothing todo | nothing todo | update; commint; |
select(读视图) | - |
当前情况下:undolog
中保存的历史版本只有一个,就是事务4.list
: 1,2,3 (当前获取的事务列表)up_limit_id
:1 (当前活跃的最小事务id)low_limit_id
:5(下一个分配的事务id)
于是可以得出当前行的事务ID(也就是trx_id
)是4,根据上方的条件判断:RC
隔离级别是可以堵到事务4提交的数据,而RR
隔离级别是读取不到的。
mysql mvvc
https://randzz.cn/bdb9d4f1f954/mysql-mvvc/