MySQL中InnoDB引擎的事务隔离级别

如果想要对MySQL中的InnoDB引擎的事务特性有深入的了解,就必须掌握它的四种事务隔离级别。如下:

  1. READ UNCOMMITTED(未提交读)
  2. READ COMMITTED(提交读)
  3. REPEATABLE READ(可重复读)
  4. SERIALIZABLE(可串行化)

READ UNCOMMITTED(未提交读)

在READ UNCOMMITTED的隔离级别下,一个事务中的修改,即使还没有被提交,对其他事务也是可见的。这有可能导致“脏读”的问题。设想一种情况,事务A开始,做了一些处理,紧接着事务B也开始,修改了一些数据,但还未提交,此时事务A读取了事务B修改的这部分数据,并用于自己的处理,但之后事务B的其他操作失败导致回滚。这时候事务B的这些修改实际上最终并未应用于数据库,但事务A却依赖了这些修改。一般情况下如果不是特别需要,不会使用READ UNCOMMITTED。

READ COMMITTED(提交读)

在READ COMMITTED的隔离级别下,一个事务只能看见已经被提交的事务做的修改。也就是说,一个事务的修改在被提交之前对其他事务都是不可见的。READ COMMITTED又被称为UNREPEATABLE READ(不可重复读),因为在一个事务中,多次读取同一个数据有可能得到不同的结果(如果有其他事务在此期间修改了这个数据并成功提交)。这是大部分数据库的默认隔离级别。

REPEATABLE READ(可重复读)

在REPEATABLE READ的隔离级别下,在同一个事务中多次读取相同记录的结果是相同的,因此它解决了“脏读”的问题。这是MySQL InnoDB的默认隔离级别。

SERIALIZABLE(可串行化)

在SERIALIZABLE是最高的隔离级别。读加共享锁,写加排他锁,读写互斥。这可能导致大量的锁争用问题,因此并发能力很低,而且经常会导致死锁的问题,一般很少使用。在某些必须保证请求串行执行的高一致性场合有可能被使用。

一些名词解释

解释一下几个重要的名词:脏读、可重复读、不可重复读、幻读、快照读、当前读和加锁读。

脏读

对于事务A和事务B来说,如果事务B对数据做了修改,但还未提交,此时如果事务A能够读取到事务B的这个数据更新,就是脏读。

可重复读

可重复读指的是,对于一个事务来说,在开始后别的事务对数据做的更新都不会被它读取到,这个事务只能读取到事务开始前数据的状态。由于在同一个事务内,多次读取同一行一数据都都会返回同一个结果(不管此时这行数据有没有被其他事务所修改),所以被称为“可重复读”。

不可重复读

假设有这样一种场景,事务A开始,读取了一行数据,然后事务B开始,修改了这行数据,然后事务B提交,之后事务A又读取了这行数据,此时事务A读取到的数据是事务B修改后的样子。由于在同一个事务内,多次读取同一行一数据可能返回不同的结果(因为其他事务修改了这行数据),所以被称为“不可重复读”。

幻读

幻读的场景是,事务A开始,用某个条件查询出了一个结果集,然后事务B开始,插入了一行数据,这行数据满足之前的查询条件,然后事务B提交,接着事务A再次用相同的条件查询结果,得到的结果比原来多了这一行事务B新提交的数据。

快照读

在REPEATABLE READ级别,由于是可重复读,实际上我们读到的是历史数据,又叫“快照读”。

当前读

插入、更新和删除操作都属于一种特殊的读操作,叫当前读。因为它们都需要读取出最新的数据而不是历史的“快照”数据。

加锁读

加锁读只出现在SERIALIZABLE级别中,该级别对读操作加共享锁,对写操作加排他锁,读写互斥。

四种隔离级别的一些特性总结:

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
READ UNCOMMITTED Yes Yes Yes No
READ COMMITTED No Yes Yes No
REPEATABLE READ No No Yes No
SERIALIZABLE No No No Yes


我们知道,行锁可以用来防止不同事务之间对数据的修改操作造成的冲突问题,但是对于插入操作却无能为力。为了满足事务的ACID特性,我们防止插入操作造成的幻读问题,因此就有了Next-Key锁。Next-Key锁是行锁和间隙锁的结合,它可以让InnoDB在REPEATABLE READ级别下不会发生别的事务插入导致的幻读。