前言:
大家都知道mysql有四大特性,原子性,一致性,隔离性,持久性,其中隔离性又有四个级别,分别是读未提交,读已提交(RC),可重复读(RR),串行化,然后mysql 的隔离性是如何解决掉的呢,带着疑问,大家一起来找答案。
1、什么是MVCC
在mysql InnoDB 存储引擎下,RC、RR是基于MVCC进行并发事务控制的,MVCC 是基于“数据版本”对并发事务进行访问。
2、实例展现
RR(可重复读):Select1=张三 Select2=张三
RC(读已提交):Select1=张三 Select2=张小三 可见RC出现了不可重复读
那么RR是怎么保证可重复读的呢,下面说。
3、MVCC基于UNDO_LOG(回滚日志) 版本链
undo_log 版本链的数据不在引用后才会被删除,不用担心数据丢失问题
以上四个事务会有如下的版本链,通过链的方式保存数据的版本变化
可以看到多出两个字段:TRX_ID(事务ID) 和DB_ROLL_PTR(指针,指向上一个版本变化的数据)
4、ReadView
4.1 什么是快照读 什么是当前读
快照读就是最普通的Select查询sql语句
当前读 指代码执行下面语句时进行读取的方式
Insert、Update、Delete、Select…for update(有锁)、Select…lock in share mode(锁),会通过行锁和间隙锁来实现。
4.2 什么是ReadView
ReadView 是"快照读"SQL执行时 MVCC 提取数据的依据
在快照读的时候才会使用到MVCC
ReadView 是一个数据结构,包含四个字段:
m_ids:当前活跃的事务编号集合。
min_trx_id:最小活跃事务编号。
max_trx_id:预分配事务编号,当前最大事务编号+1。
creator_trx_id:创建者的事务编号
在RC级别下,每次快照读都会生成ReadView
4.3 实例解析读已提交(RC)
如下图,在进行第一个select查询的时候,对应一个ReadView
如下是一个普通查询在MVCC下查找数据的过程,我们先看RC级别下是如何处理的
4.3.1 第一次查询
4.3.2 第二次查询
还是按照上面的流程,执行到事务id=2的时候,发现2<min_trx_id=3 成立,说明事务已经提交,此时读到的数据就是张小三
这就是在RC过程的结果,第一次查询张三,第二次张小三,不可重复读
4.4 实例解析可重复读(RR)
可重复读,仅在第一次执行快照读时生成ReadView,后续快照读复用
因为ReadView进行了复用,并且原始的版本链也没有变化,两次的数据读取的肯定是一样的,都是张三
4.5 RR级别下使用MVCC能避免幻读吗
能,但不完全能,MVCC不是通过锁的方式去让事务完全的隔离,当连续多次快照读,ReadView会产生复用,没有幻读问题,但是当两次快照读之间存在当前读,ReadView会重新生成,导致产生幻读
幻读:同一个事务中,同一条sql第一次查询到的数据,和第二次查询不一致,多了数据或者少了数据,称为幻读