MVCC多版本并发控制,是一种数据库管理系统并发控制的方法。MVCC多版本并发控制下,数据库中的数据会有多个版本,分别对应不同的事务,从而达到事务之间并发数据的隔离。MVCC最大的优势是读不加锁,读写不冲突,在读多写少场景中,读写不冲突可以大幅提升数据库的并发性能。
MVCC多版本并发控制
在MYSQL中,MyISAM存储引擎使用的是表锁,InnoDB存储引擎使用的是行锁。而InnoDB的事务分为四个隔离级别,其中默认的隔离级别是可重复读,可重复读要求两个并行的事务之间数据的修改互不影响,通过添加行锁的方式虽然可以实现两个事务之间数据据的修改互不影响,但是者两个事务之间存在锁等待的情况,影响数据库效率。所以InnoDB的可重复读没有采用行锁,而是使用了更为强大的MVCC。
MVCC只有在可重复读和读已提交的隔离级别下生效,其它两个隔离级别和MVCC不兼容,因为读未提交总是读最新的数据行,和事务版本无关,串行化则是会对所有读取的行加锁。由于可重复读的情况比较复杂,并且是MySQL的默认隔离级别,所以本文会用可重复读来讲解MVCC的原理。
可重复读
数据库有四种隔离级别:读未提交/读已提交/可重复读/串行化,可重复度是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到一致的数据行。
数据行的一致性包含两部分:
- 情况1:已有数据的内容变更,在同一个事务中多次查询,查询结果应该相同,如果在当前事务中进行了修改,查询结果应该和当前事务中的修改结果相同;
- 情况2:数据行的增减,同一个事务只能查看到事务开启之前数据库中数据,或者由事务本身新增/删除的结果集,无法看到开启事务期间其它事务新增或删除的结果集;
InnoDB默认的隔离级别是可重复读,可以解决以上两种情况的数据行一致性问题。其中解决情况1中的数据行一致性问题就是通过MVCC多版本并发控制实现的。
InnoDB用过Gap锁实现情况2中的数据行一致性问题,不过本文不会对Gap锁进行介绍。
MVCC的作用
MVCC可以确保同一个事务,在事务起始到结束读到的某一个数据是一致的,并且多个事务之间互不阻塞。我们以一张用户表为例,说明MVCC版本控制的作用。
首先我们需要创建用户表,并向其中插入一条用户数据,SQL语句如下:
create table user_info
(
age int ,
name varchar(255)
);
insert into user_info(age,name) value (23,'张三');
假设有A,B,C三个事务,这三个事务中在不同时刻对读取了插入用户的信息,并对用户信息进行了修改,时间线如下:
- T1时刻,事务A开始,事务A读取
age=23
的用户,该用户的name
为张三
; - T2时刻,事务B开始,事务B读取
age=23
的用户,该用户的name
为张三
; - T3时刻,事务A修改
age=23
的用户,把name
修改为李四
; - T4时刻,事务A读取
age=23
的用户,该用户的name
为李四
,事务A提交事务; - T5时刻,事务B读取
age=23
的用户,该用户的name
为张三
,事务B提交事务&#