MySQL的MVVC是个什么东东
MVVC是什么
MVVC,全称Multi-Version Concurrency Control
多版本的并发控制,Multi-Version Concurrency Control,是一个可以提升数据库并发读写性能的技术。
一般的,如果对数据的库表的一行记录进行读写操作,为了保证数据的一致性,往往需要对这一行记录进行加锁操作。而加锁带来的问题就是开销变大,性能降低。而MVVC便是对这一问题提出的一种改进策略。
快照读和当前读
首先,我们先了解一下两个概念——快照读和当前读。
当前读
当前读可以理解为,所有的当前读操作都是针对的数据库最新版本的数据,在操作的时候会对资源加悲观锁,防止其他事务对数据进行修改。
如delete、update、insert、select for update、select lock in share mode等操作均是当前读
需要注意的时,在串行化的事务隔离级别下,所有的操作均是当前读
快照读
快照读的实现是基于MVVC的,读取的可能是某个版本的快照数据。
MVCC
数据库中有哪些并发场景?
- 读-读 读操作不会造成数据一致性问题,也没有并发控制的需要
- 读-写 可能造成数据不一致,需要对线程安全进行控制,否则会造成脏读、幻读、不可重复读的错误
- 写-写 多线程存在问题,可能会造成数据丢失
MVCC能解决什么场景下的问题?
- 解决读-写场景下的并发问题,可以实现读写均不会阻塞,解决脏读、幻读、不可重复读的问题
- 不可解决写-写场景下的并发控制问题,一般可结合乐观锁或者悲观锁来实现
MVCC如何实现并发控制的?
其实现主要依靠undo日志,版本链,Read View三个技术手段。
undo日志
undo可以理解为每次针对记录行修改时,原数据的备份。每一次针对原纪录的修改都会生成一个undo日志,将原数据拷贝到日志中记录起来
- 用于事务回滚
- 是的每个事务均有自己特有的日志记录集合
undo日志一般分为插入日志和更新日志。插入日志是执行insert操作生成的日志,在事务回滚时需要使用,在事务提交后可以丢弃掉;更新日志不仅在事务回滚的时候需要,在快照读的时候也需要,不能随便删除
版本链
数据表记录的每一行均有3个隐藏列
-
db_trx_id 事务id
-
db_roll_pointer 回滚指针,指向上一个版本
-
db_row_id 隐藏的自增主键
这是一个简单的示例图。
很容易理解,每次修改都会undo日志,通过版本指针将这些日志串联起来,形成版本链。
Read View
读视图可以理解为快照读是生成的整个数据库系统的一个快照。其可以用来做可见性判断。因为每一个事务均有唯一的id,可以用此id来控制此事务可以看到的数据,可以是最新版本的,也可以是历史版本的。
其有如下几个参数:
- trx_ids 目前系统中未提交的事务id集合
- low_limit_id 最大事务版本号加1
- up_limit_id 处于活跃状态中的最好事务版本号
- creator_trx_id 创建read view的事务版本号
可见性判断代码
MVCC和事务隔离级别的关系
MVCC如何实现RR和RC的隔离级别
在RC的隔离级别下,只要提交了都可以被其他事务读取到,每一个快照读均会生成一个最新的read view
在RR的隔离级别下,为保证可重复读,每一个事务只在第一个快照读的时候才生成最新的read view,后续的快照读均不在生成快照读了,直接使用第一次快照读生成的read view,保证每一次查询结果都是一样的
那么如何解决幻读的问题?
快照读:按照MVCC的机制,可以解决幻读的问题
当前读:next-key锁(行锁+gap锁)