二,被囫囵吞枣的MVCC | 小册免费学

473 阅读2分钟

一句话描述:名为多版本并发控制的MVCC实际上就是保存了数据在某个时间节点的快照

在提到MVCC之前,不得不提下undo_log

MVCC的实现,主要是通过undo log日志版本链,和read view 来实现来实现。

  • roll_pointer指向更新事务之前生成的undo log,undo log用于事务的回滚,保证事务的原子性。
  • trx_id就是最近一次更新数据的事务ID。

执行查询时,就会开启一个read view,read view包含几个重要的东西。

  1. m_ids,就是还未提交的事务id集合
  2. low_limit_id,m_ids里最小的值
  3. up_limit_id,下一次生成事务ID最大值
  4. creator_trx_id,创建read view的事务ID,也就是自己的事务ID

因此会出现已下几种情况:

  • 如果trx_id<low_limit_id,那么说明就是之前已经提交事务的数据,直接返回。
  • 如果trx_id>low_limit,trx_id还在[ low_limit_id , up_limit_id ]范围之内,并在m_ids列表中,就说明,该数据被未提交的事务所更改,就会根据roll_pointer去查找undo log日志链,找到之前版本的数据。
  • 如果trx_id=creator_trx_id,那么说明就是自己修改的,直接返回就好了。

以上的逻辑很明显,是解决已提交读时会出现的不可重复读的问题,即保证了可重复读的隔离级别。

那么如果隔离级别是已提交读呢?

可重复读级别时,假设每次查询的时候生成了read view,后续并没有重新生成。

而读已提交级别下,则是每次查询都会生成一次read view。

因此当事务两次查询A,B之间,如果其他事务做出了提交,那么该行数据的trx_id是不会出现在B的m_ids中的,因此修改的新数据可以被读取到。

可他不是用来解决幻读的吗?

幻读其实是最简单的应用了,这是之前说过的:

  • 如果trx_id>low_limit,trx_id还在[ low_limit_id , up_limit_id ]范围之内,并在m_ids列表中,就说明,该数据被未提交的事务所更改,就会根据roll_pointer去查找undo log日志链,找到之前版本的数据。

那么如果是新的事务做出了添加,但未提交的话,他的trx_id就会在m_ids中,此时则去日志链中寻找,并发现没有这个数据。

如果已经提交了的话,那么也可以通过trx_id和creator_trx_id进行比较的方式去淘汰这行。

文章末尾请带上以下文字及链接:本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情