跳转至

MySQL事务隔离级别

SQL标准定义了四种事务隔离级别,用来平衡事务的隔离性(Isolation)和并发性能。

事务级别越高,数据一致性越好,但并发性能可能越低。

  • READ-UNCOMMITTED(读取未提交)会有脏读、幻读或不可重复读的可能
    • 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
    • 对数据一致性的保证极弱。
  • READ-COMMITTED(读取已提交)阻止脏读,仍有幻读或不可重复读仍的可能
    • 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
    • 这是大多数数据库(如 Oracle, SQL Server)的默认隔离级别。
  • REPEATABLE-READ(可重复读)阻止脏读和不可重复读,仍有幻读的可能
    • 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
    • MySQL InnoDB 存储引擎的默认隔离级别正是 REPEATABLE READ。
      • InnoDB 在此级别下通过 MVCC(多版本并发控制) 和 Next-Key Locks(间隙锁+行锁) 机制,在很大程度上解决了幻读问题。
  • SERIALIZABLE(可串行化)防止脏读、不可重复读以及幻读
    • 最高的隔离级别,完全服从 ACID 的隔离级别。
    • 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

InnoDB 的 REPEATABLE READ 对幻读的处理

通过以下机制很大程度上避免了幻读:

  • 快照读 (Snapshot Read)
    • 普通的 SELECT 语句,通过 MVCC 机制实现。事务启动时创建一个数据快照,后续的快照读都读取这个版本的数据,从而避免了看到其他事务新插入的行(幻读)或修改的行(不可重复读)。
  • 当前读 (Current Read)
    • 有变更操作的,像 INSERT, UPDATE, DELETE, SELECT ... FOR UPDATE 这些操作。
    • InnoDB 使用 Next-Key Lock 来锁定扫描到的索引记录及其间的范围(间隙),防止其他事务在这个范围内插入新的记录,从而避免幻读。
      • Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的组合。

快照读是为了“高并发”,当前读是为了“数据一致性”。