引言
在多事务并发执行中,存在脏读、幻读、不可重复读的问题。所以在数据库的发展之初,在读取以及写入数据的时候,使用了锁来保证数据读取以及写入的安全。但是加锁会带来性能问题。所以大量的工程师以及科研人员对此进行优化,针对读取和写入分别进行优化。
对于读取写操作的优化,目前使用比较多的优化思路就是 MVCC ,可以提升数据库对读取以及写入的性能。
换句话讲: 在事务并发安全执行有两种解决思路,一种是加锁,一种时使用版本控制(MVCC)的办法。单纯的只是加锁使得性能会比较低下,但是使用了版本控制之后,既可以保证运行的效率,又可以保证并发事务的安全。
不同的 DBMS ,不同的存储引擎对于 MVCC 的的实现是有所不同的,下面主要讲述的是 InnoDB 的 MVCC 的实现。更准确来说是 RR 以及 RC 两种隔离级别下面的 MVCC 的实现(因为InnnoDB只有这两种隔离级别使用了 MVCC 的思想,并且进行了具体的实现)
什么是 MVCC (狭义:InnnoDB 中 RR RC 两种隔离级别实现的底层思想)
对数据库任何修改的提交不会直接覆盖之前的数据,而是产生一个老版本和新版本的数据共存,使得在读取数据是完全不加锁。在这种情况下读取数据时,使得事务可以根据隔离级别选择读取哪儿个版本的数据。实现了多事务并发执行的安全性。
在 InnoDB 多事务并发操作中,可以设置隔离等级,选择合适的隔离等级可以解决多事务并发操作中的脏读、幻读、不可重重复读的问题。
而 InnoDB 中的隔离级别 RC(Read Committed) 和 RR(Repeatable Read) 的实现就是基于 MVCC 思想的。
RC RR 隔离级别下的 MVCC 的作用
参考知乎回答:
1. 一个事务A(txnId=100)修改了数据X,使得X=1,并且commit了
1. 另外一个事务B(txnId=101)开始尝试读取X,但是还X=1。但B没有提交。
1. 第三个事务C(txnId=102)修改了数据X,使得X=2。并且提交了
1. 事务B又一次读取了X。这时
- 如果事务B是Read Committed。那么就读取X的最新commit的版本,也就是X=2
- 如果事务B是Repeatable Read。那么读取的就是当前事务(txnId=101)之前X的最新版本,也就是X被txnId=100提交的版本,即X=1。
注意,这里B不论是Read Committed,还是Repeatable Read,都不会被锁,都能立刻拿到结果。这也就是MVCC存在的意义。
MVCC 解决了什么问题?
简而言之就是解决了在REPEATABLE READ和READ COMMITTED两个隔离级别下读取某一行数据时多事务的并发安全。
MVCC 具体的实现原理
参考
www.zhihu.com/question/27… juejin.cn/post/701616…
MVCC 使用是存在条件的,只有在快照读才会使用,在 InnoDB 的 RR RC 隔离级别下才会使用 MVCC
当前读使用的是行锁以及间隙锁实现
快照读以及当前读在 RR RC 下面执行是完全不同的
下面是 RC 级别下面的 ReadView 以及数据版本的获取:
下面是 RC 级别下面的 ReadView 以及数据版本的获取:
下面是 RR 级别下面的 ReadView 的 MVCC:
下面是 RR 级别下面的 ReadView 的 MVCC:
下面是两次快照读中间夹着一次当前读,导致了幻读问题: