Skip to content

事务的各个隔离级别是如何实现的

1. 四大隔离级别的实现

1.1 读未提交 (Read Uncommitted)

  • 现象:允许脏读、不可重复读、幻读。
  • 实现思路和原理:这是最简单的隔离级别,几乎没有隔离性。在此级别下,读取数据不会加任何锁,也不使用 MVCC。 它直接读取数据行最新的版本,即使这个版本是由一个尚未提交的事务所修改的。因此,性能最好,但数据一致性最差。

1.2 读已提交 (Read Committed)

  • 现象:解决了脏读,但仍可能出现不可重复读、幻读。
  • 实现思路和原理:这是大多数数据库(如 Oracle、PostgreSQL)的默认隔离级别。它的实现主要依赖 MVCC。
    • 读操作 (SELECT)在事务中的每一条 SELECT 语句执行前,都会创建一个新的 Read View。 这意味着,如果事务 A 在两次查询之间,事务 B 恰好修改了数据并提交,那么事务 A 的第二个 SELECT 会生成一个新的 Read View,此时就能看到事务 B 提交的修改。这就导致了“不可重复读”。由于 Read View 只能看到已提交事务的修改,因此“脏读”问题被解决。
    • 写操作 (UPDATE, DELETE):写操作仍然需要加行级排他锁,以防止多个事务同时修改同一行数据。

1.3 可重复读 (Repeatable Read)

  • 现象:解决了脏读、不可重复读,但理论上仍有幻读问题(InnoDB 在很大程度上解决了)。 这是 MySQL InnoDB 引擎的默认隔离级别。
  • 实现思路和原理:此级别的实现结合了 MVCC 和锁机制。
    • 读操作 (快照读, 普通 SELECT)只在事务开始后的第一次查询操作时创建一个 Read View,并且整个事务期间都复用这一个 Read View。 因为 Read View 是固定的,所以无论其他事务如何修改数据并提交,当前事务看到的始终是事务启动时的数据快照,从而保证了“可重复读”。
    • 写操作 (当前读, SELECT...FOR UPDATE, UPDATE, DELETE) 与幻读的解决
      • 标准的 MVCC 只能解决快照读的幻读问题。对于需要加锁的“当前读”操作,InnoDB 通过 Next-Key Lock(临键锁)来解决幻读。
      • 当一个事务执行当前读时,它不仅会锁定匹配到的记录(记录锁),还会锁定这些记录之间的“间隙”(间隙锁)。 这样一来,其他事务就无法在这个间隙中插入新的记录,从而防止了幻读的发生。

1.4 串行化 (Serializable)

  • 现象:解决了脏读、不可重复读和幻读所有问题。
  • 实现思路和原理:这是最高级别的隔离,也是最影响并发性能的。
    • 实现机制:此级别下,InnoDB 不再使用 MVCC 进行非锁定读。它会为所有的读操作(SELECT)隐式地加上共享锁(S 锁),为写操作加上排他锁(X 锁)。
    • 效果:当一个事务读取数据时,会加 S 锁,其他事务可以继续读取但不能修改。当一个事务写入数据时,会加 X 锁,其他事务既不能读也不能写。这种机制强制所有事务串行执行,一个接一个地处理,因此完全避免了并发问题,但并发性能也最低。
隔离级别 实现核心技术 读操作处理方式 写操作处理方式 解决的问题 存在的问题
读未提交 无锁 直接读取最新版本 加排他锁 (无) 脏读、不可重复读、幻读
读已提交 MVCC 每次 SELECT 创建新的 Read View 加排他锁 脏读 不可重复读、幻读
可重复读 MVCC + Next-Key Lock 事务开始时创建唯一 Read View 加排他锁和 Next-Key Lock 脏读、不可重复读、幻读(大部分) (基本解决幻读)
串行化 读写锁 所有读操作加共享锁 所有写操作加排他锁 脏读、不可重复读、幻读 并发性能差