MySQL的MVCC(Multi-Version Concurrency Control)多版本并发控制
一、前言
1、MySQL为了保证事务的隔离性,实现数据库的隔离级别,引入了MVCC
2、需要了解undo log入门。
3、需要了解快照ReadView入门。
4、先看下面的MySQL的快照读、当前读。
快照读:
读取的是记录的可见版本 (有可能是历史版本),不用加锁。简单纯粹的查询操作,属于快照读。
如:
SELECT * FROM student WHERE id=1;
当前读:
读取的是记录的最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。特殊的查询操作、插入、更新、删除操作,属于当前读。
如:
SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; //共享锁(S)
SELECT * FROM student WHERE id=1 FOR UPDATE; //排他锁(X)
INSERT INTO student VALUES (1, '张三'); //排他锁(X)
UPDATE student SET name='李四' WHERE id=1; //排他锁(X)
DELETE FROM student WHERE id=1; //排他锁(X)
插入、更新、删除都属于当前读,因为这三个操作内部就包含了一个当前读。(插入操作可能会触发Unique Key的冲突检查)
如update操作的具体流程:
- 开始执行update的sql,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁。
- 等待MySQL Server收到这条加锁的记录之后,会再发起一个update请求,更新这条记录。
- 一条记录操作完成,再读取下一条记录,直到没有满足where的条件为止。
二、MySQL里MVCC的实现
一般MVCC有2种实现方法:
- 写新数据时,旧数据不删除,而是把新数据插入。PostgreSQL就是使用的这种实现方法。
- 写新数据时,把旧数据转移到一个单独的地方,如回滚段中,其他人读数据时,从回滚段中把旧的数据读出来,如Oracle数据库和MySQL中的innodb引擎。
简单来说,MySQL的MVCC给我们提供了读取当前数据库中行数据的一种方式,如果读取的行正在执行DELETE或UPDATE操作,读取操作不会因此去等待上锁的行释放,而是去读取行的一个快照。
如图:
上图直观地展现了InnoDB一致性非锁定读的机制。之所以称其为非锁定读,是因为不需要等待行上排他锁的释放。快照数据是指该行的之前版本的数据,每行记录可能有多个版本,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control / MVCC)。InnoDB是通过undo log来实现MVCC。
在事务隔离级别RC和RR下,InnoDB默认使用MVCC方式的一致性非锁定读。
- 在RC下,一致性非锁定读总是读取被锁定行的最新一份快照数据。
- 在RR下,读取事务开始时的行数据版本。