InnoDB解决幻读的方案--LBCC&MVCC

LBCC&MVCC

InnoDB默认的事务隔离级别是repeatable read(后文中用简称RR),它为了解决该隔离级别下的幻读的并发问题,提出了LBCC和MVCC两种方案。其中LBCC解决的是当前读情况下的幻读,MVCC解决的是普通读(快照读)的幻读。至于什么是当前读,什么是快照读,将在下文中给出答案。

LBCC

LBCC是Lock-Based Concurrent Control的简称,意思是基于锁的并发控制。在InnoDB中按锁的模式来分的话可以分为共享锁(S)、排它锁(X)和意向锁,其中意向锁又分为意向共享锁(IS)和意向排它锁(IX)(此处先不做介绍,后期会专门出篇文章讲一下InnoDB和Myisam引擎的锁);如果按照锁的算法来分的话又分为记录锁(Record Locks)、间隙锁(Gap Locks)和临键锁(Next-key Locks)。其中临键锁就可以用来解决RR下的幻读问题

InnoDB 使用了两种技术来解决数据库中的幻读(phantom read)问题,即锁定读一致性控制(Lock-Based Concurrency Control, LBCC)和多版本并发控制(Multi-Version Concurrency Control, MVCC)。

1. LBCC (Lock-Based Concurrency Control)

LBCC 主要依赖锁机制来管理并发事务的隔离性。在 InnoDB 中,幻读通过 间隙锁(Gap Lock)下一键锁(Next-Key Lock) 来控制。这些锁可以防止其他事务在当前事务扫描范围内插入新的数据行,进而避免幻读现象:

  • 间隙锁(Gap Lock): 锁住一个范围之间的间隙,而不是实际的行。假设事务 A 查询范围 5 < id < 10,间隙锁会锁住这个范围,防止其他事务在此范围内插入新行。

  • 下一键锁(Next-Key Lock): 是记录锁和间隙锁的组合,锁住了特定行及其前后的间隙。这样可以更好地控制读操作范围内的插入,确保事务的隔离性。

可重复读(REPEATABLE READ) 隔离级别下,InnoDB 默认采用了下一键锁来处理幻读问题。通过这种锁机制,InnoDB 保证了在事务范围内的数据一致性。

2. MVCC (Multi-Version Concurrency Control)

MVCC 通过在不同的事务中维护数据的多个版本来处理并发读写。每个事务访问数据时,会读取与自己一致的版本,避免了对其他事务的干扰。

MVCC 使用 隐藏的版本号和事务 ID 来区分不同版本的数据:

  • 版本链: 数据行中包含一个指向旧版本的指针,形成一个版本链。当数据更新时,InnoDB 不会立即覆盖数据,而是创建一个新的版本。

  • 事务快照: 在启动时,事务会拍下一个快照,并使用该快照访问数据。这一机制让事务能够看到在其启动前的数据状态,即使后续有其他事务更改了数据。

读提交(READ COMMITTED)可重复读(REPEATABLE READ) 隔离级别下,MVCC 会帮助解决幻读问题,因为它让事务能够始终看到自己开始时的一致性视图。

LBCC vs. MVCC 应用场景

  • LBCC 更适合需要严格控制并发性和避免插入、更新导致的冲突的场景,如 可重复读隔离级别

  • MVCC 更适合高并发场景下的读操作,它让事务看到历史快照,有效减少锁竞争,提升读写性能。