mvcc简介

该文章基于innodb引擎下

操作mysql时会产生大量的并发操作,这时就涉及到锁的操作了,锁分为2种,读锁和写锁,当这条数据被读锁锁住时,其他连接可以读,不可以写,当被写锁锁住时,数据只可以被该连接读写,显然这样是无法满足业务需求的,因为太慢,并发基本为0,这时就产生了mvcc,先给大家看张简单的表(图1)

图1

很简单的表

假设现在有3条连接,如图2所示(按时间从上至下顺序排序)


图2

这时的搜索语句,搜索出的这条数据,name是什么呢

是李四

这就要说到重点了,看图3


图3

如图所见,这张表比开始的表多了2条字段,这2条字段是mysql自己定义的隐藏字段,每当对该条数据做操作,都会在undo日志中形成这样的数据,分别是trx_id(操作这条数据的事务id),roll_pointer(回滚指针)

在图2中,session a中开启的事务编号为1 session b开启的事务编号为2 对应着图3中的trx_id这时就到了mvcc的最后一步 ReadView

ReadView是一个事务快照,准确来说是当前时间点系统内活跃的事务列表,也就是说系统内所有未提交的事务,都会记录在这个Readview内,事务就根据它来判断哪些数据是可见的,哪些是不可见的

查询一条数据时,事务会拿到这个ReadView,去到undo log中进行判断。若查询到某一条数据:

先去查看undo log中的最新数据行,如果数据行的版本号小于ReadView记录的事务id最小值,就说明这条数据对当前数据库是可见的,可以直接作为结果集返回

若数据行版本号大于ReadView记录最大值,说明这条数据是由一个新的事务修改的,对当前事务不可见,那么就顺着版本链继续往下寻找第一条满足条件的

若数据行版本号在ReadView最小值和最大值之间,那么就需要进行遍历了整个ReadView了,如果数据行版本号等于ReadView的某个值,说说明该行数据仍然处于活跃状态,那么对当前事务不可见

那又是如何实现读已提交和可重复读呢?其实很简单,就是生成ReadView的时机不同。

对读已提交来说,事务中的每次读操作都会生成一个新的ReadView,也就是说,如果这期间某个事务提交了,那么它就会从ReadView中移除。这样确保事务每次读操作都能读到相对比较新的数据

而对可重复读来说,事务只有在第一次进行读操作时才会生成一个ReadView,后续的读操作都会重复使用这个ReadView。也就是说,如果在此期间有其他事务提交了,那么对于可重复读来说也是不可见的,因为对它来说,事务活跃状态在第一次进行读操作时就已经确定下来,后面不会修改了。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容