电商类网站开发合同书,互联网产品做网站好还是小程序,wordpress网站怎么建,国外域名注册公司什么是MVCC#xff1f;
MVCC全称 Multi-Version Concurrency Control#xff0c;即多版本并发控制#xff0c;维持一个数据的多个版本#xff0c;主要是为了提升数据库的并发访问性能#xff0c;用更高性能的方式去处理数据库读写冲突问题#xff0c;实现无锁并发。
什…什么是MVCC
MVCC全称 Multi-Version Concurrency Control即多版本并发控制维持一个数据的多个版本主要是为了提升数据库的并发访问性能用更高性能的方式去处理数据库读写冲突问题实现无锁并发。
什么是快照读和当前读
快照读不加锁非阻塞读快照读要求数据库隔离级别不能是串行化否则会退化到当前读快照读是基于多版本并发控制的因为是基于多版本并发控制所以快照读可能读取的不是最新的数据。当前读当前读就是读取最新的数据版本快照读读取的时候会对读取的数据加锁读取的时候其他事务不能修改当前数据。
MVCC和快照读、当前读的关系?
MVCC 多版本并发控制而快照就是数据的一个版本MVCC 的无锁并发就是依赖快照读机制实现的。
MVCC的实现原理?
MVCC 实现依赖于数据库记录中的三个隐式字段、undo日志、Read View 版本链本篇讨论皆基于 MySQL 的 InnoDB 存储引擎。
三个隐式字段
隐式字段是我们正常来看看不到的字段数据库的每行数据除了我们看到的字段之外还有三个我们看不到的字段。
DB_TRX_ID记录当前事务最后一次修改的事务ID即事务 ID事务 ID 是递增的。DB_ROW_ID隐藏的自增主键ID如果数据库没有主键ID数据库会自动生成一个 6个字节的 DB_ROW_ID。DB_ROLL_PTR回滚指针指向上一个数据版本。
简单图例 undo log 日志
我们都知道undo log 日志是回滚日志是数据库保证数据一致性的一个支撑当出现异常情况时候通过 undo log 日志来进行数据回滚其实它还有其他作用undo log 又分为两种如下
insert undo loginsert 操作时候产生的日志只会在发生异常需要进行回滚的时候使用事务提交后undo log 就没有用处了就会被丢弃。update undo log 和 delete undo log这两类 undo log 不仅在事务回滚时候要用到同时在快照读的时候也会用到。
undo log 也会记录一条版本链表每次修改数据的时候数据库会先把当前数据拷贝一份到 undo log中然后再对数据进行修改最在undo log 中最新修改的数据副本会在链的头部同时它有一个回滚指针指向他的上一个版本。
Read View
Read View 是事务执行快照读产生的视图在事务执行快照读的时候系统会以当前时刻生成一个快照以此来维护系统此时活跃的事务id用来做可见性判断当某个事务进行快照读的时候我们根据 Read View 来判断当前事务可以读取哪个版本的数据然后就去该数据的 undo log 里面找数据当然也可能是读取最新的数据。
Read View 遵守可见性规则它的三个属性如下
trx_list用来维护 Read View 生成时候系统活跃的事务ID是一个列表。up_limit_id活跃事务ID中最小的ID。low_limit_idRead View 生成时候系统将要分配的下一个事务ID。 可见性算法主要是把要修改的数据的最新版本的事务ID即DB_TRX_ID取出来与当前系统中活跃的其他事务ID去对比而Read View 就维护了这些活跃的事务ID如果在 Read View 中找不到合适条件的数据记录就会去 undo log 日志根据回滚指针 DB_ROLL_PTR 来找数据记录直到找到为止。 Read View 的比较流程如下
注意事务ID 是递增的。
第一步比较 DB_TRX_ID up_limit_id 是否小于活跃事务 Read View中最小的事务ID如果小于则当前事务能看到 DB_TRX_ID 所在的记录否则进入第二个判断。第二步比较 DB_TRX_ID low_limit_id 是否大于等于下一个将要发生的事务ID如果大于等于则代表 DB_TRX_ID 所在的记录在 Read View生成后才出现的那对当前事务肯定不可见否则进入第三个判断。第三步 判断 DB_TRX_ID 是否在活跃事务 Read View 之中如果在则代表我 Read View 生成时刻你这个事务还在活跃还没有Commit你修改的数据我当前事务也是看不见的如果不在则说明这个事务在 Read View 生成之前就已经 Commit 了因为第一步、第二步已经判断了是否小于最小活跃事务ID和是否是将要发生的事务ID两者都不是同时又不在 活跃事务 Read View 中只能说明在这个事务 Read View 在当前是事务发生之前了当前事务理所当然能够看到。
简易流程如下 读已提交(Read Committed)、可重复读(Repeatable Read) 隔离级别下的快照读的区别
读已提交(Read Committed)、可重复读(Repeatable Read) 隔离级别下的快照读最大的区别就是生成 Read View 时机不同。
可重复读(Repeatable Read) 隔离级别下一个事务只有在第一次读取数据的时候生成一个Read ViewRead View 记录当前活跃的事务ID后面继续读取数据时候如果用到快照读那他使用的还是第一次读取时候的 Read View这也是为什么可重复读(Repeatable Read) 隔离级别下看不到别的事务的修改记录的原因。读已提交(Read Committed) 隔离级别下事务开启后每次使用快照读的时候都会重新生成一个活跃事务ID第一读取和第二次读取使用的不是同一个 Read View那第二次读取的时候第一次读取时候的 Read View 中的某些事务可能已经提交了那在第二次快照读的时候就可以看到了这也是在读已提交(Read Committed) 隔离级别下可以看到别的事务提交的记录的原因 。
MVCC解决了什么问题
想要知道MVCC解决了什么问题我们要先知道数据库多个事务并发访问会有什么问题数据库并发访问场景如下
读读并发多个事务同时读取同一份数据不存在问题无需进行并发控制。读写并发多个事务同时读写同一份数据有线程安全问题可能会脏读、幻读、不可重复度问题。写写并发多个事务同时对同一份数据写可能会有更新丢失的情况。
而MVCC 就是解决以上三种并发中的读写并发问题是一种无所并发控制可以解决脏读、不可重复读问题可以解决部分场景的幻读问题。
什么是幻读MVCC可以解决幻读问题吗
MVCC 可以解决快照读的幻读问题MVCC 机制是依赖 快照读、undo log、Read View 来实现的可以解决快照读的幻读问题但是不能解决 update、delete 的幻读问题因为这些操作是当前读。
以下讨论基于可重复读(Repeatable Read) 隔离级别。
当前读幻读演示
时间事务A事务B1开始事务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提交事务
流程解释
在第2个时间点的时候快照读可以得到 id 大于 1的数据。在第6个时间点的时候虽然时间点4插入了一条 id 为6的数据并且在时间点5提交了事务但是时间点6还是查询不到 id 为6的这条数据查询结果和第2个时间点的查询结果没有区别。在第7个时间点的时候查询结果就有了变化因为 update 操作是当前读而事务B在第5个时间点已经提交了一条 id 为6的数据根据当前读的规则此刻是可以读取到 id 为6 的数据也就可以更新 id 为 6 的数据。第8个时间点的时候执行第三次查询此时是基于当前最新版本查询的所以会查询到事务B提交的 id 为6的数据对比第一次、第二次查询多出了 id 为6的数据这就是幻读。
当前读的幻读问题怎么解决
加锁解决关于锁的介绍传送门如下
MySQL–锁机制详解
#共享锁
SELECT * FROM user LOCK IN SHARE MODE;
# 排他锁
SELECT * FROM user FOR UPDATE;
# 排他锁
INSERT INTO user
# 排他锁
UPDATE user
# 排他锁
DELETE FROM user 注意INSERT、UPDATE 、DELETE 操作数据库默认加排他锁。
解决幻读问题演示
时间事务A事务B1开始事务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阻塞了处于等待状态7select * from user where id 58提交事务9事务A提交了释放了间隙锁事务B 执行 INSERT 操作10提交事务
在第2个时间点的时候使用 lock in share mode 语法显示加锁了不仅表中存在的数据加锁了而且还给 id5 的区间加了间隙锁。因为时间点2的操作给 id5 的区间加了间隙锁 所以事务B 在时间点5的时候执行 INSERT 操作的时候出现了阻塞。因为时间点5的 INSERT 操作被阻塞了所以这次查询的数据跟时间点2的查询结果完全一致。事务B想要执行 INSERT 成功必须要等待事务A 提交事务释放锁这就解决了幻读问题。
MVCC可以解决更新丢失问题吗
MVCC 解决的是读写并发问题而更新丢失是写写并发问题MVCC不能解决更新丢失问题更新丢失依赖数据库的隔离级别来解决。
如有不正确的地方请各位指出纠正。