南京玄武网站建设,什么网站可以做告白的网页版,小程序定制语言,如何查看网站的建设者多版本并发控制#xff08;MVCC#xff09;
MVCC一直是数据库部分的高频面试题#xff0c;这篇文章来聊聊MVCC是什么#xff0c;以及一些底层原理的实现。
当前读和快照读#xff1a;
当前读#xff1a;读取的是事务最新的版本#xff0c;读取的过程中其他并发事务不…多版本并发控制MVCC
MVCC一直是数据库部分的高频面试题这篇文章来聊聊MVCC是什么以及一些底层原理的实现。
当前读和快照读
当前读读取的是事务最新的版本读取的过程中其他并发事务不能进行修改需要对读取的记录进行加锁。快照读不加任何锁的select语句就是快照读。假如在可重复读隔离级别下事务A进行select先后两次读取而事务B在两次读取过程中修改了数据并提交了事务那么事务A读到的就不是最新版本的数据。如果想读到最新版本的数据需要在读取的过程中加锁如select ... lock in share mode. 读已提交隔离级别下每次select都是一次快照读因为每次读都可能读取到的是其他事务已经提交的增删改操作可重复读隔离级别下开启事务后第一次select才是快照读因为其后的select读取不到其他事务提交的增删改操作串行化隔离级别下每次select都是一次当前读因为每次读取都会加锁
MVCC的概念
MVCC即多版本并发控制维护一个数据的多个版本使得不同事务之间的读写操作没有冲突。什么是版本一行记录修改前和修改后就是两个不同的版本。
MVCC的实现原理
MVCC依靠三样东西来实现隐藏字段、undo log、readview创建一个表的时候InnoDB会给表加上三个隐藏字段****DB_TRX_IDDB_ROLL_PTRDB_ROLL_ID DB_TRX_ID最近一次修改这一行记录的事务的id。比如DB_TRX_ID 4表示最近一次修改这行 记录的事务是4。DB_ROLL_PTR回滚指针指针指向这行记录的上一个版本用于配合undo log回滚日志来找到这行记录的上一个版本执行增删改之前的版本DB_ROLL_ID隐藏主键。如果表没有指定主键的时候会自动生成。如果已经指定了主键就不会生成。 undo log在insert的时候undo log只在回滚的时候需要在事务提交后可以立即删除不需要记录上一个版本该行的数据因为上一版本该行不存在在update、delete的时候不仅回滚的时候需要多版本并发控制的时候也需要用来记录上一数据版本用于多版本并发控制因此事务提交后也不会立即删除。 undo log版本链 readview每次事务执行快照读都有可能会生成readview。决定快照读读取的是undo log版本链中的哪一条历史记录。readview记录的是当前活跃中未提交的事务的id包含以下四个字段 m_ids当前正在活跃中的事务的集合min_trx_id最小的活跃中的事务idmax_trx_id不是当前正在活跃中的事务集合的最大id而是预分配的事务id即最大活跃中的事务id1因为事务id是自增的因此加一creator_trx_idreadview创建者的事务id版本链数据的访问规则trx_idundo log记录的当前事务的id即隐藏字段DB_TRX_ID用这个id去匹配下面的规则如果符合其中某一条件说明当前版本是可以读取的如果不符合条件说明这个版本的数据不能读就会顺着版本链去寻找更老的版本的数据 如果trx_id creator_trx_id说明数据就是当前事务修改的因此是可以读取到的如果trx_id min_trx_id说明当前事务不是活跃中的事务已经提交已提交的数据版本是可以读取到的如果trx_id max_trx_id说明当前事务是在readview生成后才开启的因此不可以访问该版本的数据如果min_trx_id trx_id max_trx_id且 trx_id不属于活跃中的事务的集合说明该事务数据已经提交已提交的数据版本是可以读取到的readview的生成时机不同隔离级别生成时机不同。如果是读已提交隔离级别那么在事务中每次执行快照读都会生成readview如果是可重复读隔离级别那么只在事务第一次执行快照读的时候生成readview后续会复用这个readview
MVCC演示
读已提交隔离级别在这种隔离级别下每一次快照读都会生成一个readview在事务5中第一次快照读会有三个活跃中的事务3、4、5第二次快照读由于事务3已经提交因此只有两个活跃中的事务4和5。 第一次快照读此时有三个活跃中的事务3、4、5 最近一次对id 30这行记录进行修改的事务id是4即trx_id 4均不符合版本链数据的访问规则因此顺着版本链去寻找更老版本的数据即trx_id 3trx_id 3也均不符合版本链数据的访问规则继续寻找trx_id 2trx_id 2时符合第二条规则trx_id2 min_trx_id3小于最小的正在活跃中的事务id说明trx_id 2这个事务已经提交了结合读已提交隔离级别的宏观理解并发事务是可以读取到其他事务已经提交的数据的因此查询结果就是trx_id 2对应的版本 第二次快照读此时有两个活跃中的事务4、5。 最近一次对id 30这行记录进行修改的事务id是4即trx_id 4均不符合版本链数据的访问规则因此顺着版本链去寻找更老版本的数据即trx_id 3trx_id 3时符合第二条规则trx_id3 min_trx_id4小于最小的正在活跃中的事务id说明trx_id 3这个事务已经提交了结合读已提交隔离级别的宏观理解并发事务是可以读取到其他事务已经提交的数据的因此查询结果就是trx_id 3对应的版本 可重复读隔离级别在这种隔离级别下只在事务第一次执行快照读的时候生成readview后续再读取的时候会复用这个readview。以下过程和读已提交隔离级别的过程相同唯一的区别是读已提交隔离级别两次执行快照读都会生成新的readview因而两次读取的结果不同而可重复读隔离级别两次执行快照读的readview都相同因而读取结果相同。上述过程就是不可重复读的底层原理。
第一次快照读此时有三个活跃中的事务3、4、5 最近一次对id 30这行记录进行修改的事务id是4即trx_id 4均不符合版本链数据的访问规则因此顺着版本链去寻找更老版本的数据即trx_id 3trx_id 3也均不符合版本链数据的访问规则继续寻找trx_id 2trx_id 2时符合第二条规则trx_id2 min_trx_id3小于最小的正在活跃中的事务id说明trx_id 2这个事务已经提交了结合读已提交隔离级别的宏观理解并发事务是可以读取到其他事务已经提交的数据的因此查询结果就是trx_id 2对应的版本 第二次快照读复用第一次采用的readview因此读取结果相同。