MVCC 全名Multi Version Concurrency Control 多版本控制, 是指在数据库中为了实现高并发的数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能看到自己应该看到的数据版本。
MVCC 在MySQL Innodb中的实现主要是为了提高数据库的并发性,更好的处理读写冲突问题。
MVCC的实现分为三个部分: 表中三个隐藏的字段、 undo log日志、 read view
mysql中每行记录除了我们自定义的字段外,还有三个隐藏的字段:
实际还有一个删除flag 隐藏字段, 如果数据被删除或更新,并非真的删除,只是改变删除flag。
之前介绍过undo log主要用来实现数据库回滚和mvcc。这里我们就看看它如何实现mvcc
undo log 主要分为两种:
其中只有update undo log能配合完成mvcc操作。
下面我们看一下undo log 的记录过程:
从上面我们可以知道,不同或相同的事务对同一行数据的操作,在undo log中会生成一条记录版本的线性表。链表的头结点是最新版的数据记录,链尾是最早的数据记录。
Read View 是事务进行快照读操作时产生的读视图(Read View), 主要是用来做可见性判断。
在一个事务执行快照读的时候,会生成数据库系统当前的一个快照, 记录并维护当前活跃事务的ID(当每个事务开启时,就会被分配一个递增的ID,所以最新的事务ID最大 )。
Read View 工作原理主要包含三个部分:
从上面的介绍我们看到了MVCC是如何实现事务间的隔离的,而mysql事务隔离有四种级别:
隔离级别 | 存在的问题 |
---|---|
READ-UNCOMMITTED (RU) | 脏读、不可重复读、幻读 |
READ-COMMITTED (RC) | 不可重复读、幻读 |
REPEATABLE-READ (RR) | 幻读 |
SERIALIZABLE (SE) |
RU是不存在事务的隔离的,SE的锁级别完全屏蔽了数据库的并发效果。因此这里只需要讨论RC和RR两种级别在MVCC中的差别。
RR是RC的更高一级隔离级别,在RC的基础上解决了不可重复读的问题。我们来比较一下两者的快照读的区别:
1、事务开启后,先进行查询生成快照
表1: 事务B在事务A提交后,查询的数据依然是500,而当前数据已经更新成400
事务A | 事务B |
---|---|
开启事务 | 开启事务 |
快照读(无影响)查询金额为500 | 快照读查询金额为500 |
更新金额为400 | |
提交事务 | |
select 快照读 金额为500 |
|
select lock in share mode当前读 金额为400 |
2、事务开启后,先不进行查询,等另一事务提交后再生成快照
表2:
事务A | 事务B |
---|---|
开启事务 | 开启事务 |
快照读(无影响)查询金额为500 | |
更新金额为400 | |
提交事务 | |
select 快照读 金额为400 |
|
select lock in share mode当前读 金额为400 |
二者唯一的区别是,表1中先生成快照,后被事务A修改数据;表2先被事务A修改数据,后生成快照,二者数据的可见性完全不同。由此可以看出事务中快照读的结果与该事务首次出现快照读的时机有很大关系,它决定了事务后续快照读的结果。
因此RR与RC数据的隔离性与它们的快照生成时间有关。
总之在 RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;而在 RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View, 之后的快照读获取的都是同一个 Read View