MVCC 概述
MVCC 是什么?
Multi-Version Concurrency Control(MVCC)即多版本并发控制,是一种并发控制方法,一般用于实现对数据库的并发访问。特点:不依赖锁机制(无锁非阻塞式并发)却能避免同一数据在并发事务之间的竞争,以较低开销的方式提高数据库的并发性能。
MVCC 的使用在 MySQL 数据库哪些地方有体现呢? InnoDB 是如何实现 MVCC 的呢?
接下来将通过这篇文章进行解答。
1. 事务隔离性问题
在介绍 MVCC 之前,先了解一些关于 数据库事务 的前置知识。
事务的隔离性(Isolation)
事务具有 原子性、一致性、隔离性、持久性 四个特性,这些特性数据库是根据不同的技术实现的,这篇文章主要讲解的是 隔离性。
隔离性(Isolation):数据库允许多个并发事务同时对数据进行读写和修改的能力。当多个用户并发访问数据库时,每个用户开启的事务不能被其他事务所做的操作干扰,实现多个并发事务之间相互隔离。隔离性可以防止多个并发事务执行时由于交叉执行导致数据不一致的问题。
MySQL数据库的事务隔离性可以通过 MVCC 或者 加锁 的方式来实现。
脏读、不可重复读、幻读
并发事务场景下,读-写冲突(事务之间相互影响)导致出现 脏读、不可重复读、幻读 的事务隔离性问题。
事务隔离性问题 概述如下:
- 脏读:一个事务读取了另一个事务未提交的数据,这些数据随时可能会被回滚,导致事务可能读到脏数据(过期数据)。
- 不可重复读:在一个事务中多次执行同一查询语句,由于其他事务的修改操作,导致当前事务的前后两次查询返回的结果(记录)不一致。
- 幻读:在一个事务中多次执行同一查询语句,由于其他事务的插入或删除操作,导致当前事务的前后两次查询返回的结果集(记录数量)不一致。
数据库如何避免 脏读、不可重复读、幻读 现象的呢? 接着往下看。
2. 事务的隔离级别
SQL 标准提出 四种隔离级别 来避免脏读、不可重复读、幻读现象。
四种隔离级别如下(隔离级别从低到高):
- READ-UNCOMMITTED(读未提交):允许读取并发事务尚未提交的数据。
- READ-COMMITTED(读提交)):允许读取并发事务已经提交的数据。
- REPEATABLE-READ(可重复读):在同一事务中,多次执行同一查询语句返回的结果一致。
- SERIALIZABLE(可串行化):所有的事务串行执行。
四种隔离级别出现脏读、不可重复读、幻读的情况(✅表示可能出现 ❌表示不可能出现):
隔离级别越高,能避免事务隔离性问题越强,但是对应的并发性能效率也就越低。
MySQL 的 InnoDB 引擎默认隔离级为 可重复读。
关于这四种隔离级别数据库是如何实现的?
读未提交:可以读取未提交的数据(允许脏读),所以允许事务直接读取(不需要加锁) 最新数据即可。
读提交:只允许读取已提交的数据,需要避免脏读,所以在每次查询时,获取通过最新的版本快照来判断哪些是已提交的数据从而避免脏读。(这里是基于 MVCC 实现的,具体的后续文章会讲解)
可重复读:同一事务多次读取同样记录,需要返回结果一致。所以在事务第一次读取数据时,获取当前的版本快照,通过快照的方式保证事务执行期间与事务启动时看到的数据一致,即使其他事务修改了数据也不会影响当前事务,从而实现可重复读。(这里也是基于 MVCC 实现的,具体后续文章会讲解)
可串行化:需要完全服从ACID的特性,所以需要事务之间严格串行执行,通过加读写锁的方式实现串行执行即可。
3. 当前读与快照读
前面说到 MySQL 的 InnoDB 引擎默认隔离级别为