Mysql MVCC机制讲解
一 概述
在MySQL InnoDB存储引擎下
RC(读已提交)、RR(可重复读)基于MVCC(多版本并发控制)进行并发事务控制
MVCC是基于”数据版本”对并发事务进行访问
从上图我们来解读:
如果在RC级别下:事物D在第一次查询得出的是张三,第二次读取的时候,由于第二次提交已经生效,所以读取出来的是张小三,出现了不可重复读
在RR级别下:事务D两次读取都是张三
接下来我们看上述操作,mysql底层都记录了什么:
mysql底层针对上述操作,写入了一份给予UNDO_LOG的日志链:
日志链的最上层是最后数据库落盘的数据,即最后提交的张老三,事务编号为3,最后的字段DB_ROLL_PTR是指针信息,指向了上一次记录的数据信息。
疑问:undo_log不实在事务回滚之后就会删除吗?如果食物编号2回滚后,岂不是链表就断掉了?
UNDO_LOG版本链不是立即删除,MySQL确保版本链数据不再被“引用”后再进行删除。可以参考jvm的可达性分析以及三色标级原理去理解。
那么日志链到底有什么作用呢?我们引入一个概念:ReadView。
什么是快照读?
快照读其实就是指的常规的select语句,readView就是快照读提取MVCC数据的依据。
与其对应的,还有一个当前读,是执行下列语句时进行的数据读取方式:
Insert、Update、Delete、
Select...for update
Select...lock in share mode
readView的数据结构组成:
- m_ids:当前活跃的事务编号集合
- 1min_trx_id:最小活跃事务编号
- max_trx_id:预分配事务编号,当前最大事务编号+1
- creator_trx_id:ReadView创建者的事务编号
readView不同的场景:
RC:每一次执行快照读时生成readView,如图:
在执行快照读语句的时候生成了对应的readView。
m_id:2,3,4 为什么没有1? 因为1已经提交了,不再活跃
min_trx_id: 活跃最小id,2
max_trx_id: 预分配事务id,5
creator_trx_id: 创建此快照的事务id,4
第二条select语句生成的readView如上理解。
我们来看一下生成readView之后的数据访问逻辑:
上面的所有过程其实总结就一句话:从最新的事物开始判断,是否是不活跃的,即已经提交的,只有已经提交的数据可以访问,所以当前第一次select只有针对trx_id = 1的那条数据才具备访问的权限,所以返回的就是张三。
可重复读生成的readView的情况:
仅在第一次执行快照读时生成ReadView,后续快照读复用
(有例外:后面会说)
RR情况下使用MVCC可以解决幻读吗?
能,但不完全能!
原因:当在事务的过程中产生了新增,删除操作,对于快照读是不可见的,即当两次快照读中间插入了当前读,即会产生幻读。