多版本并发控制(MVCC, Multi-Version Concurrency Control) 是一种用于管理数据库并发访问的技术。它允许多个事务并发地读取和写入数据库,而不会相互干扰,从而提高了数据库的并发性能和一致性。只有写写会相互阻塞。

基本概念

  1. 版本控制

    • 每个数据项(如行)都有多个版本,每个版本代表了不同事务对数据的不同修改。
    • MVCC 通过为每个事务和数据版本分配时间戳或事务 ID,来管理数据的不同版本。
  2. 事务视图

    • 每个事务在开始时会创建一个视图,这个视图包含了数据库在事务开始时的快照(readview)
    • 事务可以在自己的视图中读取数据,并不会受到其他事务未提交修改的影响。
  3. 读操作

    • 读操作会访问数据的快照版本,不会阻塞其他事务的写操作。
    • 读操作可以看到在事务开始前已经提交的数据,而无法看到其他事务中未提交的变更。
  4. 写操作

    • 写操作会创建数据的新版本,并记录在数据库中。
    • 当事务提交时,新版本的数据会被写入数据库,其他事务将能看到这个新的数据版本。

优点

  • 减少锁竞争:通过提供数据的快照,减少了读取操作的锁竞争,提高了并发性能。
  • 提高并发性:多个事务可以同时读取和修改数据而不会互相阻塞。
  • 事务隔离:确保每个事务只看到在其开始时已提交的数据,提供了高隔离级别的并发控制。

MVCC 的实现

  • 行版本控制:通常使用隐藏的时间戳或事务 ID 来标记每个数据行的不同版本。
  • 快照隔离:数据库会维护一个系统级别的时间戳或事务 ID 列表来管理不同事务的快照。

示例

假设有两个事务,A 和 B,进行对同一数据的读取和写入:

  1. 事务 A:开始时读取数据行,并且在数据行的快照中查看数据。
  2. 事务 B:对相同的数据行进行写入和修改。
  3. 事务 A:读取到的是事务 A 开始时的数据快照,不会受事务 B 修改的影响。
  4. 事务 B:提交修改后,数据行的版本更新,其他事务会看到这个新的数据版本。

总结

MVCC 通过为每个事务创建独立的视图和版本,允许多个事务同时读取和修改数据,提供了高效的并发控制和隔离机制。它减少了对锁的需求,提高了数据库的并发处理能力,适用于高并发的应用场景。

事务 B:提交修改后,此时事务A再次读取得到的是提交修改后的还是事务 A 开始时的数据快照

MVCC(多版本并发控制)的实现下,事务 A 和事务 B 的读取行为如下:

  1. 事务 A 开始时会获得数据库的快照,这个快照是事务 A 开始时的数据库状态。
  2. 事务 B 在事务 A 进行读取时,可能对数据进行修改并提交。
  3. 事务 A 在事务 B 提交后再次读取数据,仍然会看到事务 A 开始时的数据快照,而不是事务 B 提交后的数据。

解释

  • 事务 A 的视图:事务 A 在其开始时创建了一个视图,这个视图包含了数据库在事务 A 开始时的状态。任何在事务 A 期间提交的其他事务的修改(如事务 B 的修改)对事务 A 是不可见的。
  • 事务 B 的提交:事务 B 的提交会创建一个新的数据版本,并且该版本对事务 B 及其之后开始的事务是可见的。
  • 事务 A 的读取:事务 A 在任何时刻(包括事务 B 提交后)读取数据时,依然是基于其开始时的快照数据,不会受到事务 B 提交的影响。只有在事务 A 结束后,其视图会过期,事务 A 之后的新事务才会看到事务 B 提交后的数据版本。

总结

事务 A 的读取结果在其生命周期内是稳定的,会基于事务开始时的快照数据进行读取。即使其他事务(如事务 B)进行了提交和修改,事务 A 也不会受到这些修改的影响,直到事务 A 完成并结束。

MVCC的关键机制:版本链(version chain)与回滚指针(rollback pointer)

版本链 是一种单向链表,由新版本指向上一个版本,用的就是回滚指针。

应用:

  • 数据快照:通过版本链,数据库能够提供事务开始时的数据快照,确保事务在执行期间看到的是一致的数据状态。在 MVCC 实现中,回滚指针用于维护数据项的历史版本。虽然事务回滚是一个重要的用途,但回滚指针主要用来管理和维护数据的不同版本,使得系统能够在任何时间点提供一致的视图。
  • 通过回滚指针可以实现回滚或恢复操作