目录
MVCC介绍:
MVCC全称是多版本并发控制 (Multi-Version Concurrency Control),只有在InnoDB引擎下存在。MVCC机制的作用其实就是避免同一个数据在不同事务之间的竞争,提高系统的并发性能。
它的特点如下:
- 允许多个版本同时存在,并发执行。
- 不依赖锁机制,性能高。
目录
- 只在读已提交和可重复读的事务隔离级别下工作。
MVCC是用来做什么的?为什么要设计并使用它?
- 提高性能
MVCC在某些情况下可以避免使用锁机制,可在并发时提升性能
- 解决事务隔离级别问题,防止出现不可重复读和幻读问题
MVCC如何实现多版本控制?
MVCC实现多版本控制是通过Undo_Log版本链和Read View来达成的
Undo_Log版本链如图所示,每次有事务执行update和delete操作时,数据库会将该操作记录到undo_log日志文件中,其中每条记录都有一个roll_pointer,可用于版本的回滚。
ReadView是MVCC中的新概念,其本质上就是一个数据结构,可控制当前事务应该关心最近哪些事务进行的操作,和应该忽略哪些事务进行的操作,从而达到事务隔离的效果。
其包含四个变量:
m_ids:
表示正在活跃(即没有提交)的所有事务id的集合
min_trx_id:
表示当前活跃事务集合中最小的事务id
max_trx_id:
表示当前活跃事务集合中最大的事务id + 1,即下一次开启事务应该分配的id
create_trx_id:
创建当前Read View的事务id
介绍完了,undo_log版本链和read view,我们现在来分析一下其是如何控制事务隔离的吧
如下图所示,当前事务的id为201(刚被创建,当前使用的read view是上一个事务创建的),我们
现在要用这个事务执行查询操作,看看其如何控制隔离级别:
我们需要四步操作:
第一步,查看undo_log版本链,看当前指针指向记录的事务id是否==当前的creator_trx_id,如果等于,则说明当前操作由当前事务(即自己)操作的数据,当然可以查看
若不满足第一步,则执行第二步
第二步,将当前指针指向的事务id与min_trx_id作比较,若小于,则说明该事务在当前read view生成之前就已经提交,可以使用,无需执行第四步
若不满足第二步,则执行第三步
第三步,将当前指针指向的事务id与max_trx_id作比较,若大于,则说明该事务在当前read view生成之后才开启,不能被访问,无需执行第四步
若二、三都不满足,即trx_id在[min_trx_id,max_trx_id]之间,则执行第四步
第四步,看当前指针指向的trx_id是否在m_ids中,如果不在,则说明该事务再创建read view之前已经提交,可以使用,不在则继续回滚版本,然后重复执行第一步,从而解决脏读问题
MVCC可以解决不可重复读和幻读问题吗?
可以,但是不能完全解决幻读问题
InnoDB
存储引擎在 RR 级别下通过 MVCC
和 Next-key Lock
来解决幻读问题:
1、执行普通 select
,此时会以 MVCC
快照读的方式读取数据
在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View
,并使用至事务提交。所以在生成 Read View
之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2、执行 select...for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB
使用 Next-key Lockopen in new window 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读