1. 概念
MVCC:Multi-Version Concurrency Control,多版本并发控制
处理什么事情:提高数据库的并发性能,处理读写冲突(实现无锁并发)
当前读:共享锁、排它锁(读锁、写锁),会对读取的记录加锁,其他事务无法修改它。
快照读:不加锁的select,基于MVCC实现,读到的可能不是数据的最新版本。
MVCC是一个理想模型,快照读是MySQL实现MVCC非阻塞读功能的实现。
MVCC为每个修改保存一个版本,读操作只读该事务开始前的数据库的快照
在并发读写时,读操作和写操作不用互相阻塞,提高并发读写性能。
解决了数据库的事务隔离问题,但是不能解决更新丢失问题。
2. 实现原理
3个隐式字段(db_row_id、db_trx_id、db_roll_ptr)、undo日志、Read View
- db_row_id:数据库默认为该行生成的唯一隐式主键(怎么改都不变)
- db_trx_id:当前操作该记录的事务ID(一般从1递增)
- db_roll_ptr:回滚指针,用于配合undo,指向上一个旧版本。
undo日志分为insert undo log和update undo log
前者只在事务回滚时需要,事务提交后可以丢弃。后者在事务回滚和快照读时都需要,不能随便删除。
undo log为一条记录版本的链表,链首为最新记录,链尾为最早记录
Read View:就是事务进行快照读时产生的读视图,我们通过一些算法判断版本链中哪个版本数据可用。
3. 判断原则
Read View如何判断版本链那个版本可用?
Read View有四个参数
-
m_ids
当前活跃事务的id列表(未commit) -
min_trx_id
m_ids的最小值(最早生成的事务) -
max_trx_id
要分配给下一个事务的id -
creator_trx_id
当前读取操作的事务id
一个事务对应一个版本的数据!
我们要读取的事务id定义为trx_id
-
trx_id == creator_trx_id
表示读取的是我自己修改后的数据,可以读取。 -
trx_id < min_trx_id
表示要读取的事务肯定是已经提交的事务,可以读取。 -
trx_id > max_trx_id
表示要读取的事务已经不在版本链了,无法读取。 -
min_trx_id < trx_id < max_trx_id
如果trx_id在m_ids中(活跃事务),无法读取;否则可以读取。
4. RC和RR
可重复读RR和读已提交RC
事务中快照读的结果是非常依赖该事务首次出现快照读的地方,有决定后续快照读结果的能力。
RR隔离级别下,快照读生成Read View时,之前的修改对当前事务可见,之后的修改均不可见。之后的读操作读的都是这次快照读生成的Read View。
RC隔离级别下,每次快照读操作都会生成一份Read View,所以读到的都是最新的数据。