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 更适合高并发场景下的读操作,它让事务看到历史快照,有效减少锁竞争,提升读写性能。