MVCC(多版本并发控制)
是数据库系统中的一种并发控制技术,用于解决多个事务同时读写数据时的并发问题。其核心思想是通过为每个事务提供一个数据的“快照”版本来避免加锁,从而实现高并发下的读写操作,同时保证数据的一致性。
MySQL的InnoDB存储引擎下RC、RR且快照读下基于MVCC做数据的多版本并发控制
当前读和快照读
- 当前读:读取的数据是最新版本,读取数据时还要保证其他并发事务不会修改当前的数据,当前读会对读取的记录加锁
select ... lock in share mode(共享锁); select ... for update | insert | delete (排 他锁)
- 快照读: 每一次修改数据都会在undo log 中存有快照记录,就是读取undo log中的某一版本的快照,优点是无须加锁,缺点是读取到的数据可能不是最新的版本
select ...
MVCC实现原理
- 隐藏字段
row_id 当数据库表没定义主键时,InnoDB会以row_id为主键生成一个聚簇索引
trx_id 操作这条记录的事务id
rollpointer 回滚指针,通过回滚指针连起来实现undolog版本链
- undo版本链
- readview
隐藏字段和undo版本链决定了返回的数据,具体返回哪个版本由readview + 版本链访问规则/可见性算法决定
readview:
1. <font style="background-color:#FBDE28;">m_ids</font> 当前活跃的事务id集合
2. <font style="background-color:#FBDE28;">max_trx_id </font> 最大事务id(+1) 生成ReadView时系统应该分配给下一个事务的id
3. <font style="background-color:#FBDE28;">min_trx_id </font>m_ids中最小事务id
4. <font style="background-color:#FBDE28;">creator_trx_id</font> readview创建者事务id
版本链访问规则:
MVCC在RC、RR下的不同表现
RC:每次都是读取最新的readview(另一个线程修改数据,当前事务能够感知到)
RR:读取的事务开始时的readview
同事务内,RC可能两次快照读返回的是不用版本的记录
而RR则两次快照读返回的是相同版本
解释了为什么RC有不可重复读问题,RR是可重复读
MVCC解决了什么问题
MVCC在快照读解决了幻读现象,这也是为什么说Innodb很大程度上解决了幻读
update、delete等当前读用的间隙锁和临键锁给数据上锁,别的事务就写不了了
当两个都是快照读或两个都是当前读情况下,幻读确实被解决了,但是当一个是快照读另一个是当前读的情况下幻读依然存在,比如一个事务里先select再insert,select得到的是经过MVCC限制过版本的数据而非最新数据,但insert读取的数据是最新的数据,此时这个数据可能已经被其它事务修改了,这就导致了幻读