MySQL——多版本并发控制(MVCC)

114 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

1、MVCC概述

MVCC(Multiversion Concurrency Control),多版本并发控制,提供并发访问数据库时,对事务内读取到的内存做处理,用来避免写操作堵塞读操作的并发问题。

顾名思义,多版本并发控制(MVCC)是通过数据行的多个版本(通过==undo log回滚行记录到某个版本==体现多版本)管理来实现数据库的并发控制。这项技术使得在InnoDB在事务隔离级别下执行一致性读(也叫快照读)操作有了保证。

换言之,一致性读就是为了查询一些正在被另一个事务更新的行记录,并且可以看到它们被事务更新之前的值(如果读到了正在被事务更新的值,就是发生了脏读的情况),这样在做查询的时候就不用等待另一个事务释放锁,就可以直接读到数据而不用加锁。

MVCC没有正式的标准,在不同的DBMS中 MVCC的实现方式可能是不同的,也不是普遍使用的(大家可以参考相关的DBMS 文档)。这里介绍InnoDB中 MVCC的实现机制(MySQL其它的存储引擎并不支持它)。

undo log

在执行事务操作之前,把需要操作的数据备份到undo log中,若查询数据就有undo log +不在undo log的数据(事务未提交之前),undo log一般是逻辑日志,用来回滚行记录到某个版本。

redo log

在执行事务操作完一条语句后,将最新的数据备份到redo log中,记录的是数据页的物理修改,通常是物理日志,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

2、快照读和当前读

MVCC在MySQL 的InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读—写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读,而这个读指的就是快照读,而非当前读。当前读实际上是一种加锁的操作,是悲观锁的实现。而MVCC本质是采用乐观锁思想的一种方式。

2.1、快照读

读取的是快照版本:undo +未修改的表的数据。

快照读又叫一致性读,读取的是快照数据。不加锁的简单的SELECT 都属于快照读,及不加锁的非阻塞读;比如:

select * from student where...

之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于MVCC,它在很多情况下,避免的加锁操作,减低了开销。

既然是基于多版本,那么快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

快照读的前提是隔离级别不是串行级别,串行级别的快照读会退化成当前读(不是一个一个读的,一个一个读就会读取到最新的行,那就是当前读)。

2.2、当前读

当前读读取的是最新版本(最新数据,而不是历史版本的数据),读取时会对读取记录加锁,通过锁机制来保证读取的数据无法被其他并发事务修改。加锁的 SELECT ,或者增删改都会先进行当前读,以保证读到最新的记录。