MySQL 的 MVCC(多版本并发控制) 是 InnoDB 存储引擎中实现事务隔离的核心机制之一,它通过维持多个数据版本来支持并发事务的执行。MVCC 的目标是让不同事务能够读取和修改数据而不相互阻塞,提升数据库的并发性能。
1. MVCC 背后的基本思想
MVCC 的基本思想是:每个事务会看到在它开始时的数据库状态,而不会被其他事务的操作影响。即使其他事务在此期间修改了数据,当前事务依然能够看到它开始时的数据快照,而不会读取到其他事务修改中的数据。
2. MVCC 的实现原理
在 InnoDB 中,MVCC 主要通过 事务 ID、回滚日志、一致性视图 等机制来实现:
2.1 每行数据的隐式字段
每行数据除了存储实际的数据值之外,还包含三个隐式字段:
- 事务 ID(trx_id):表示创建或修改该行数据的事务 ID。每当一行数据被插入或更新时,InnoDB 会记录当前事务的事务 ID。
- 回滚指针(roll_ptr):指向数据行的前一个版本(如果有),当数据被修改时,可以通过回滚指针追溯到该行的历史版本。
- 删除标志(delete_flag):用于标记该数据行是否已经被删除,通常用于软删除操作。
2.2 Undo 日志
InnoDB 使用 Undo 日志 来记录数据的历史版本。Undo 日志记录了数据修改前的值,以便支持事务回滚操作。当事务对数据进行修改时,会在 Undo 日志中保存旧的数据版本。如果事务需要回滚,可以通过 Undo 日志将数据恢复到修改前的状态。
2.3 一致性视图(Read View)
每个事务在开始时都会创建一个 一致性视图(Read View)。一致性视图记录了所有正在执行的事务的事务 ID。事务读取数据时,会参考一致性视图,确保只读取那些已经提交的事务的数据。如果某个数据行的创建或修改事务的事务 ID 在一致性视图中,则该数据对当前事务不可见。
一致性视图用于保证 快照读(Snapshot Read) 的一致性,即在事务开始时就固定了它可以看到的版本,而不会受到其他事务的修改影响。
3. 事务的读写操作
3.1 快照读(Snapshot Read)
快照读是指一个事务读取它开始时的数据快照。快照读不会受当前正在进行的其他事务的影响,因此它读取的数据是事务开始时的一致视图。这是通过一致性视图来实现的。
例如,如果事务 A 在 t0 时刻开始,它会通过一致性视图看到所有在 t0 之前已经提交的事务的数据版本。在事务 A 执行期间,即使其他事务插入或修改了数据,事务 A 仍然只能看到在 t0 时刻已提交的事务数据。
3.2 当前读(Current Read)
当前读是指一个事务读取最新的、正在进行中的数据。当前读会考虑到其他事务的提交,可能会看到其他事务正在执行的修改。
例如,如果事务 A 执行当前读操作来读取某行数据,且在事务 A 进行读取时,事务 B 正在修改这行数据,则事务 A 读取到的将是事务 B 提交后的最新版本。
4. 事务隔离级别与 MVCC 的关系
MVCC 在不同的事务隔离级别下有不同的行为。MySQL 中主要有四个事务隔离级别:
-
读未提交(Read Uncommitted):允许事务读取其他事务未提交的数据,可能会发生脏读。MVCC 在这个级别下并不会提供太多的隔离性,容易产生脏读和不可重复读的问题。
-
读已提交(Read Committed):事务只能读取已经提交的其他事务的数据,避免了脏读。但在同一事务内多次读取相同的数据可能会发生不可重复读问题。
-
可重复读(Repeatable Read):保证事务内多次读取相同数据时,结果始终一致。InnoDB 通过 MVCC 实现了 可重复读 级别,保证在事务期间读取到的数据是事务开始时的快照,避免了不可重复读,但仍然可能发生幻读。
-
串行化(Serializable):该隔离级别要求事务串行化执行,保证完全的隔离性。虽然避免了所有并发问题,但性能开销较大,通常较少使用。
对于 可重复读 级别,InnoDB 使用 MVCC 来保持多个版本的记录,并通过一致性视图确保事务读取的版本在整个事务生命周期内保持一致。
5. MVCC 如何避免锁冲突
MVCC 的关键优势之一就是它减少了对行锁的依赖。在高并发的情况下,多个事务可以并发执行,并且不需要相互等待锁。例如:
- 事务 A 可以在读取数据时使用快照读,这样即使其他事务 B 对数据进行修改,A 也不会被阻塞。
- 当事务 B 提交更改时,这些更改只会影响事务 B 后续的查询,而不会影响事务 A 当前的查询。
因此,MVCC 使得事务之间能够并发执行,同时保证数据的隔离性和一致性,极大提高了数据库的并发性。
6. MVCC 中的数据清理(垃圾回收)
尽管 MVCC 允许多个版本的并发访问,但为了防止历史版本积累过多,InnoDB 会定期清理过期的数据版本。当一个事务提交后,它所创建的数据版本可能会成为“过时版本”,这些版本会在没有事务引用它们时被删除。这是通过 回收线程 来实现的,回收线程会定期扫描数据库并清理那些没有任何事务引用的数据行版本。
7. MVCC 的优势
- 减少锁竞争:MVCC 通过允许事务并发读取历史版本的数据,减少了事务间对资源的竞争。
- 提高并发性能:多个事务可以并发执行,特别是在读取操作时,不会被其他事务的修改操作阻塞。
- 实现高效的事务回滚和恢复:通过 Undo 日志和回滚指针,InnoDB 可以在事务失败时恢复到之前的状态。
8. 总结
InnoDB 中的 MVCC 通过引入事务 ID、Undo 日志、回滚指针和一致性视图来实现多个事务对数据库的并发访问。它使得数据库能够在保证数据一致性的同时,提高并发性能。MVCC 支持可重复读、快照读等操作,并通过历史版本的数据管理避免了大量的锁竞争,是高并发环境下数据库性能优化的关键技术之一。