MVCC(多版本并发控制)底层原理总结:

MVCC 是通过维护数据的多个版本来控制并发访问的技术,它使得数据库能够支持高并发事务,同时保证事务之间的隔离性和一致性。在 MySQL 的 InnoDB 存储引擎中,MVCC 是通过 隐藏列ReadView 快照undo log 来实现的。

1. 关键概念:

  • 隐藏列(Hidden Columns):为了支持 MVCC 机制,InnoDB 在每一行数据中隐藏了两个额外的列,分别是 DB_TRX_IDDB_ROLL_PTR。这两个列并不直接暴露给用户,但它们对 MVCC 的工作至关重要。DB_TRX_ID 存储了最近修改该行数据的事务 ID,而 DB_ROLL_PTR 存储了指向该行数据历史版本的指针。
  • ReadView 快照:为了支持事务隔离级别(如“读已提交”或“可重复读”),InnoDB 会在每个查询操作时创建一个 ReadView 快照。该快照存储了当前查询事务的 ID、所有未提交事务的事务 ID(按升序排列)以及未开始的事务 ID。通过这些信息,数据库可以判断查询事务能看到哪些数据版本。
  • Undo Log(回滚日志):记录事务对数据的修改操作。当事务修改数据时,InnoDB 会为该数据生成一个新的版本,旧版本数据会保存在 undo log 中。

2. ReadView 快照内容:

  • 当前查询事务 ID:表示当前正在执行查询的事务 ID。
  • 未提交事务的事务 ID(按升序排列):记录了当前未提交事务的事务 ID,从最小到最大排序。
  • 未开始的事务 ID:记录那些尚未开始的事务 ID。

3. Undo Log 数据读取逻辑:

当执行查询操作时,InnoDB 会根据当前事务的 ReadView 快照信息来判断能读取到哪些数据版本。这一过程通过以下几个步骤实现:

  • 当前查询事务 ID = Undo Log 里的事务 ID:如果数据的事务 ID 与当前查询事务的 ID 匹配,说明该数据是当前事务修改的,当前事务可读取该数据。
  • Undo Log 事务 ID < 未提交事务的最小事务 ID:如果 Undo Log 中的事务 ID 小于未提交事务的最小事务 ID,说明该数据是在当前查询事务开始之前就已经提交的,因此该数据可被读取。
  • Undo Log 事务 ID > 未开始事务的最大事务 ID:如果 Undo Log 中的事务 ID 大于未开始事务的最大事务 ID,说明该数据是在查询事务开始之后的并发事务中进行修改的,当前事务不能读取此数据。此时,需要根据 Undo Log 的指针查找下一条数据。
  • Undo Log 事务 ID 在未提交事务的最小事务 ID 和最大事务 ID 之间:如果 Undo Log 中的事务 ID 位于未提交事务的最小和最大事务 ID 之间,说明该数据是在并发的未提交事务中修改的,当前查询事务不能读取此数据。此时,查询会再次进行上述判断,直到找到符合可读条件的数据。

4. 读已提交隔离级别的处理:

  • 读已提交 隔离级别下,每次查询的时候都会创建 ReadView 快照,根据这个快照去 Undo Log 里边找到数据,查找到符合条件的最新版本数据。
  • 在执行查询时,如果数据修改是未提交事务所做的,查询将跳过该数据,直到找到符合条件的数据。

5. 可重复读隔离级别的处理:

  • 可重复读 隔离级别下,创建 ReadView 快照只会在第一次读取时进行,后续的查询会使用相同的 ReadView 快照。因为可重复读第一次读的数据和之后读的数据一致,所以只需在第一次读的时候创建快照。
  • 由于同一个快照被多次复用,事务中的读取操作可以获得一致的数据版本,避免了“不可重复读”的问题。

6. 隐藏列的作用:

  • DB_TRX_ID:每一行数据中都会有一个 DB_TRX_ID 列,它记录了最后修改该行数据的事务 ID。当查询需要检查某行数据时,InnoDB 会根据 DB_TRX_ID 来判断该行数据是否是当前事务能够读取的。如果该行的事务 ID 比当前查询事务的事务 ID 早(即该数据在查询开始时已提交),则该数据对查询事务可见。
  • DB_ROLL_PTR:该列指向了该行数据历史版本的 Undo Log 指针。如果查询的数据版本不可见,InnoDB 会根据 DB_ROLL_PTR 查找该数据的历史版本,继续查找直到找到一个符合条件的可见数据版本。

7. 总结:

  • MVCC通过 隐藏列ReadView 快照Undo Log 来实现数据的并发控制,保证高并发环境下的数据一致性和事务隔离性。
  • 读已提交和可重复读的隔离级别分别通过每次查询创建 ReadView 快照(读已提交)或仅在首次读取时创建快照(可重复读)来控制数据的可见性。
  • 通过比较 Undo Log 中的事务 ID 与当前 ReadView 快照中的信息,InnoDB 判断一个数据版本是否可见,从而保证数据的隔离性。

今夜有点儿凉
40 声望3 粉丝

今夜有点儿凉,乌云遮住了月亮。