【视频笔记】数据库中的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

所以在可重复读的隔离级别下,两次查询的结果时一样的!

 

参考:数据库中的MVCC到底是个啥?_哔哩哔哩_bilibili

posted @ 2025-06-10 17:02  fanblog  阅读(9)  评论(0)    收藏  举报