MVCC简单介绍

MVCC的中文是多版本并发控制,他只在读已提交和可重复读两种事务隔离级别起作用。

MVCC原理

废话不多说,直接说原理。

MVCC的实现需要三样东西

  1. MySQL数据记录的隐藏字段:db_trx_id、db_roll_ptr

    db_trx_id存储的是这条记录最后的事务ID。比如有一条数据,他是由id=1的事务插入的,那么db_trx_id是1;后面又被id=2的事务更新了,db_trx_id是2
    db_roll_ptr:是指向undo log日志链的指针。什么是undo log日志链呢?下面介绍

  2. undo 日志版本链

    一条记录被插入的时候会在undo log中生产一条记录,记录了该行的所有数据,已经事务id,这个事务id是最关键的。同理,更新的时候也会在undo log日志链里加一条记录,并记录这个事务的idundo log日志链如图所示

  1. 每次查询都会产生的查询快照-ReadView

    MySQL在查询是会产生一个叫Readview的东西,他也会产生一个事务id。这个事务id跟上面undo log日志链里的事务id是一样的东西,而且事务id都是自增长的。

重要的原理来了

接下来就是原理的介绍了。首先MySQL插入一条数据的时候,undo log日志链会生成一条历史版本记录,如下图

接下来解读一下上面的图

MySQL在插入一条记录的时候,也就是执行insert语句的时候,会在undo log日志链里生成一条记录(最下面的一条),其中前三项是该条记录的数据,trx_id表示执行事务id,这里是2.
接着执行了数据的update操作,同样会生成一条记录,也会记录执行update操作的事务id。这几条记录会通过roll_pointer回滚指针连在一起,形成日志链

那么这么多条记录,查询的时候是怎么知道拿哪一条的呢?直接拿最上面那一条有没有问题?

假设此次查询的Readview事务id是6,Readview看到这日志链,最先接触到的是第一条,事务id为7的,他一看这事务id比自己的大,不应该拿。至于原因是这样的:上面说过事务id是自增的,序号是7的事务肯定比序号是5的事务要晚。既然事务id为7的不能取,那就往下走,。看到事务id是5的记录。5比6小,这总可以取值了吧。还是不行,还需要检查一下id为5的事务是不是还在活跃(MySQL有事务活跃列表),还在活跃就表示事务还没提交。注意MVCC是在读已提交和可重复读两种事务隔离级别起作用,没提交的事务记录也不能取。再往下遇到事务id是4的记录,且该事务不在事务活跃列表里(事务已经提交了),那这条数据就是此次查询的结果了!

总结

以上就是简单的理解MVCC的原理。MVCC还有很多细节,如果理解好原理,再去看细节,想必更容易学习。
最后再做个总结,方便大家面试的时候用:MVCC依赖三样东西,分别是:MySQL数据行的隐藏字段,undo log日志链和Readview。事务在插入和更新操作的时候,都会形成undo log日志链,undo log日志链会记录该次操作的事务id,这个日志链会跟数据行的回滚指针关联起来。MySQL执行查询的时候会生成Readview,他也会生成事务id。Readview会用自身的事务id和undo log日志链的事务id做比较, 当undo log日志链的事务id等于或小于自己的事务id,undolog上的事务已经提交,该undo log上的数据就是此次查询的结果。

最后祝大家面试顺利!