1、总结先行

​ Mysql的Innodb存储通过MVCC乐观锁的方式来保证了可重复读隔离级别下事务的幻读问题

MVCC的核心就是Undo Log+ Read View,“MV”就是通过Undo Log来保存数据的历史版本,实现多版本的管理,“CC”是通过Read View来实现管理,通过Read View原则来决定数据是否显示。同时针对不同的隔离级别,Read View的生成策略不同,也就实现了不同的隔离级别

2、事务的隔离级别和异常问题

隔离级别/异常 脏读 不可重复读 幻读
读未提交
读已提交
可重复读
串行化

在MySQL中,默认的隔离级别是可重复读,可以解决脏读和不可重复读的问题,但不能解决幻读问题。如果我们想要解决幻读问题,就需要采用串行化的方式,也就是将隔离级别提升到最高,但这样一来就会大幅降低数据库的事务并发能力。

  • 哪Mysql中是咋么在可重复读隔离级别解决幻读的呢?

​ - 答案是: MVCC + Next-Key Lock

3、MVCC简介

MVCC的英文全称是Multiversion Concurrency Control,中文翻译过来就是多版本并发控制技术。从名字中也能看出来,MVCC是通过数据行的多个版本管理来实现数据库的并发控制,简单来说它的思想就是保存数据的历史版本。这样我们就可以通过比较版本号决定数据是否显示出来(具体的规则后面会介绍到),读取数据的时候不需要加锁也可以保证事务的隔离效果。

通过MVCC我们可以解决以下几个问题:

  1. 读写之间阻塞的问题,通过MVCC可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
  2. 降低了死锁的概率。这是因为MVCC采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。
  3. 解决一致性读的问题。一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

3.1、快照读&当前读

那么什么是快照读呢?快照读读取的是快照数据。不加锁的简单的SELECT都属于快照读,比如这样:

SELECT * FROM player WHERE ...

当前读就是读取最新数据,而不是历史版本的数据。加锁的SELECT,或者对数据进行增删改都会进行当前读,比如:

SELECT * FROM player LOCK IN SHARE MODE;
SELECT * FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...

这里需要说明的是,快照读就是普通的读操作,而当前读包括了加锁的读取和DML操作。

4、InnoDB中MVCC的实现

4.1、事务版本号

4.2、行记录的隐藏列

4.3、Undo Log