赞
踩
什么是MVCC?
MVCC全称 Multi-Version Concurrency Control,即多版本并发控制,维持一个数据的多个版本,主要是为了提升数据库的并发访问性能,用更高性能的方式去处理数据库读写冲突问题,实现无锁并发。
什么是快照读和当前读?
MVCC和快照读、当前读的关系?
MVCC 多版本并发控制,而快照就是数据的一个版本,MVCC 的无锁并发就是依赖快照读机制实现的。
MVCC 实现依赖于数据库记录中的三个隐式字段、undo日志、Read View 版本链,本篇讨论皆基于 MySQL 的 InnoDB 存储引擎。
三个隐式字段:
隐式字段,是我们正常来看看不到的字段,数据库的每行数据除了我们看到的字段之外,还有三个我们看不到的字段。
简单图例:
undo log 日志:
我们都知道undo log 日志是回滚日志,是数据库保证数据一致性的一个支撑,当出现异常情况时候,通过 undo log 日志来进行数据回滚,其实它还有其他作用,undo log 又分为两种,如下:
undo log 也会记录一条版本链表,每次修改数据的时候,数据库会先把当前数据拷贝一份到 undo log中,然后再对数据进行修改,最在undo log 中最新修改的数据副本会在链的头部,同时它有一个回滚指针指向他的上一个版本。
Read View:
Read View 是事务执行快照读产生的视图,在事务执行快照读的时候,系统会以当前时刻生成一个快照,以此来维护系统此时活跃的事务id,用来做可见性判断,当某个事务进行快照读的时候,我们根据 Read View 来判断当前事务可以读取哪个版本的数据,然后就去该数据的 undo log 里面找数据,当然也可能是读取最新的数据。
Read View 遵守可见性规则,它的三个属性如下:
可见性算法主要是把要修改的数据的最新版本的事务ID,即DB_TRX_ID取出来,与当前系统中活跃的其他事务ID去对比,而Read View 就维护了这些活跃的事务ID,如果在 Read View 中找不到合适条件的数据记录,就会去 undo log 日志根据回滚指针 DB_ROLL_PTR 来找数据记录直到找到为止。
Read View 的比较流程如下:
注意事务ID 是递增的。
简易流程如下:
读已提交(Read Committed)、可重复读(Repeatable Read) 隔离级别下的快照读的区别?
读已提交(Read Committed)、可重复读(Repeatable Read) 隔离级别下的快照读最大的区别就是生成 Read View 时机不同。
MVCC解决了什么问题?
想要知道MVCC解决了什么问题,我们要先知道数据库多个事务并发访问会有什么问题,数据库并发访问场景如下:
而MVCC 就是解决以上三种并发中的读写并发问题,是一种无所并发控制,可以解决脏读、不可重复读问题,可以解决部分场景的幻读问题。
什么是幻读?MVCC可以解决幻读问题吗?
MVCC 可以解决快照读的幻读问题,MVCC 机制是依赖 快照读、undo log、Read View 来实现的,可以解决快照读的幻读问题,但是不能解决 update、delete 的幻读问题,因为这些操作是当前读。
以下讨论基于可重复读(Repeatable Read) 隔离级别。
当前读幻读演示:
时间 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询:select * from user where id > 1; | |
3 | 开始事务 | |
4 | 执行insert: INSERT INTO user (id, user_name, user_code, age, address, hobby)VALUES(6, ‘赵六’, ‘TC-00000006’, 26, ‘广西’, ‘羽毛球’); | |
5 | 提交事务 | |
6 | 第二次查询:select * from user where id > 1; | |
7 | 修改数据:update user set name = ‘赵六国’ where id = 6; | |
8 | 第三次查询:select * from user where id >1; | |
9 | 提交事务 |
流程解释:
当前读的幻读问题怎么解决?
加锁解决,关于锁的介绍,传送门如下:
#共享锁
SELECT * FROM user LOCK IN SHARE MODE;
# 排他锁
SELECT * FROM user FOR UPDATE;
# 排他锁
INSERT INTO user
# 排他锁
UPDATE user
# 排他锁
DELETE FROM user
注意:INSERT、UPDATE 、DELETE 操作数据库默认加排他锁。
解决幻读问题演示:
时间 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询:select * from user where id > 5 lock in share mode; | |
3 | 事务A显示加了间隙锁 | |
4 | 开始事务 | |
5 | 执行insert: INSERT INTO user (id, user_name, user_code, age, address, hobby)VALUES(6, ‘赵六’, ‘TC-00000006’, 26, ‘广西’, ‘羽毛球’); | |
6 | 阻塞了,处于等待状态 | |
7 | select * from user where id > 5 | |
8 | 提交事务 | |
9 | 事务A提交了,释放了间隙锁,事务B 执行 INSERT 操作 | |
10 | 提交事务 |
MVCC可以解决更新丢失问题吗?
MVCC 解决的是读写并发问题,而更新丢失是写写并发问题,MVCC不能解决更新丢失问题,更新丢失依赖数据库的隔离级别来解决。
如有不正确的地方请各位指出纠正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。