MVCC多版本并发控制
MVCC
是多版本并发控制(Multi-Version Concurrency Control,简称MVCC),是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现已提交读和可重复读隔离级别的实现,也经常称为多版本数据库。MVCC机制会生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本(系统版本号和事务版本号)。
MVCC多版本并发控制中,读操作可以分为两类:
快照读(snapshot read)
读的是记录的可见版本,不用加锁。如 select
当前读(current read)
读取的是记录的最新版本,并且当前读返回的记录。如insert,delete,update,select…lock in share mode/for update
MVCC:每一行记录实际上有多个版本,每个版本的记录除了数据本身之外,增加了其它字段
DB_TRX_ID:记录当前事务ID
DB_ROLL_PTR:指向undo log日志上数据的指针
已提交读:每次执行语句的时候都重新生成一次快照(Read View),每次select查询时。
可重复读:同一个事务开始的时候生成一个当前事务全局性的快照(Read View),第一次select查询时。
快照内容读取原则
1、版本未提交无法读取生成快照
2、版本已提交,但是在快照创建后提交的,无法读取
3、版本已提交,但是在快照创建前提交的,可以读取
4、当前事务内自己的更新,可以读到
已提交读和可重复读的问题
已提交读(READ-COMMITTED
)和可重复读(REPETABLE-READ
)的底层实现就是使用了 MVCC
(多版本并发控制),其提供了并发读取方式 快照读;
innodb
提供了两个读取操作:锁定读 和 非锁定读,MVCC提供了一个快照读,依赖于底层的undo log 即回滚日志
已提交读
已提交读解决了 脏读的问题,但没有解决幻读问题,是因为:
每一次select
都会产生一次新的数据快照,但必须满足数据已被事务正确commit
了。
但是没法解决 不可重复读,因为,每次select都会产生一次新的数据快照,其他事务更新后且已commit的数据,可实时反馈到当前事务的select中,所以解决了脏读问题。
没有解决幻读是因为每次select都会产生一次新的数据快照,其他事务增加了新的记录行并且已成功提交,导致当前事务以同样条件查询时,出现记录数的改变了。
可重复读
一个事务中只有第一次select
产生快照,且只产生一次,这样后面再select
都是查看第一次的快照,例如:
先设置两个会话都为可重复读级别并开始事务,然后会话2先查询产生快照
紧接着,会话1 修改该行记录:update user set age = 20 where id=7;
然后会话2 再次进行相同查询结果仍相同
这就是因为,select第二次就是用第一次select保存的快照了
正因如上所述,能够解决了不可重复的问题。同时也部分解决了幻读的问题,但是当前事务自己做的事务修改和更新数据是能被 select 出来的
undo log回滚日志主要作用
事务发生错误时回滚 rollback
;
提供了MVCC
的非锁定读(快照读)undo logo