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的时候活跃的idup_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/