【视频笔记】数据库中的MVCC到底是个啥?
MVCC全称:Multi Version Concurrency Control 多版本并发控制
当对一个表,先进行写操作,再进行读操作,就要等写操作完了之后,才能进行读操作,这就是所谓的读写冲突。
要是在并发比较高的情况下,性能就会比较低下,而mvcc就是要解决这个问题,让读写不再冲突。
这里的读指的是“快照读”,除了快照读,还有另一种“当前读”。
常规的select操作就是快照读,select name from person where id = 1
当前读就是要读取最新的值。(既然是最新的,就要在对应的数据上加锁,也就相当于悲观锁)像select ... for update, insert.. , update.., delete..,
mvcc实在读提交(read commited)和可重复度(repeatable read)隔离级别下生效的。它其实是根据“版本管理”和“判断规则”来得到最终的结果的。
例子:如下4个事务,同时开始执行,执行的顺序都是从上往下
事务1的update语句是在事务4的第一个select之后执行的,到这里undolog就要上场了。
事务4的第一次select执行时,事务2和事务3的update语句,都已经完成修改,不论是否提交,undolog都会把事务102和103以节点的形式进行存放。
因为102先操作,所以103是最新的,103要在上面。从新到旧的顺序来排列,执行就是从上到下的顺序了。
节点直接要用回滚指针来进行连接
除了这两个事务节点,还有没执行事务时,初始记录的节点,同样也要关联起来
还有个重要的东西叫readview,这个东西是在当前读取的时候,产生的一个视图。
对应在事务中,就是进行select快照读的时候,在这一瞬间产生的数据保存下来,当做快照;这样其他事务在修改数据时,就不会影响到这个快照视图了。
readview中还有重要的4个属性:
m_ids: 活跃中的事务ID列表(指的是正在执行但没有提交的事务ID)
min_trx_id: 活跃中的最小事务ID,也就是m_ids中的最小值
max_trx_id:分配给下一个事务的ID,是生成readview所在事务ID+1
creator_trx_id:生成readview时所在的事务ID
针对这四个属性,就有相对应的判断规则(视频位置:05:16附近)
根据4个条件,划分出5个区域来
首先满足第一个条件的话,就是当前的事务;接着有min_trx_id这个边界,小于此边界的就是已提交的事务;然后就是max_trx_id这个边界,大于此边界,就是当前事务后新开启的事务;在这两个边界中,又分为在m_ids中,这部分就是未提交的事务,而不在m_ids中就是已提交的事务。
两个已提交的事务和当前事务,都是可以访问的
而剩下的未提交事务,和当前事务后新开启的事务,就是都不能访问的。
结合上面例子
这四个属性确定好值之后,再把判断规则拿过来,接着再把undolog引用链也拿过来
第一个判断条件是否等于当前事务(也就是104)很明显不等于(103 !=104)
接着第二个判断条件,是否小于min_trx_id,也就是是否小于101,很明显也不小于(103 !< 101)
第三个判断条件,是否大于max_trx_id, 也就是是否大于105, 很明显也不大于(103 !> 105)
最后第4个判断条件,是否在min_trx_id和max_trx_id中,这时是在其中的。继续判断是否在m_ids中,m_ids值是101和104,很明显不在;这就符合下面的条件了,也就是可以访问的。所以我们能看到的就是事务103的值,也就是查询的结果时axing3(select name from person where id = 1)
而刚才这个查询是事务104下的第一个查询,下面还有第二个查询,在两次查询之间,事务101已经提交了。
分析第二次查询,这时要分为不同的隔离级别来看。读提交、可重复度两种隔离级别。
# 首先看读提交的隔离级别
当第二个查询时,会重新生成readview,而事务101已经提交了,就要看生成的readview变成了什么样
再把undolog的列表和判断规则拿过来,因为事务101完成了修改,也提交了,所以undolog又多了一个事务101的节点,依然是从上往下来执行
先看第一个节点,事务101,
第一个判断条件,是否等于当前事务,也就是是否等于104,很明显不等于;
接着第二个判断条件,是否小于min_trx_id, 也就是是否小于104,很明显小于,这就符合可以查看到的条件,所以我们能查看到的就是事务101的值,也就是查询的结果是axing1。
这个事务104的第二次查询,是在隔离级别为读提交的条件下,能看到两次读结果确实也是不一样的。第一次查询的结果时axing3,第二次查询的结果时axing1。
# 在事务隔离级别为可重复读的条件下,第二次查询结果是什么呢?
可重复读的关键就是,第二次查询不会再重新生成readview,而是用第一次查询的readview
那就把第一次查询的readview和新的undolog拿过来,再看一下判断的过程。先看第一个节点,事务101
第一个判断条件,是否等于当前事务104,很明显不等于;
接着第二个判断条件,是否小于min_trx_id(101),很明显也不小于
第三个判断条件,是否大于max_trx_id(105),很明显也不大于
第四个判断条件,min_trx_id<=trx_id<=max_trx_id, 很明显在区间内;继续判断是否在m_ids里(101,104),很明显,在里面,那就是不可以访问的。
所以事务101节点,就拜拜掉
接着就下一个节点,到这里,就和读提交隔离级别下的第一次查询情况一模一样了吗? 结果是事务103的结果,都是axing3
所以在可重复读的隔离级别下,两次查询的结果时一样的!