先做网站后台还是前台,东莞市企业信息查询网,wordpress苏醒主题安全吗,郑州seo询搜点网络效果佳全称Multi-Version Concurrency Control#xff0c;即多版本并发控制#xff0c;主要是为了提高数据库的并发性能。
1、版本链 对于使用InnoDB存储引擎的表来说#xff0c;它的聚簇索引记录中都包含两个必要的隐藏列#xff1a;
1、trx_id#xff1a;每次一个事务对某条… 全称Multi-Version Concurrency Control即多版本并发控制主要是为了提高数据库的并发性能。
1、版本链 对于使用InnoDB存储引擎的表来说它的聚簇索引记录中都包含两个必要的隐藏列
1、trx_id每次一个事务对某条聚簇索引记录进行改动时都会把该事务的事务id赋值给trx_id隐藏列。 2、roll_pointer每次对某条聚簇索引记录进行改动时都会把旧的版本写入到undo日志中然后这个隐藏列就相当于一个指针可以通过它来找到该记录修改前的信息。 为了实现事务的原子性InnoDB存储引擎在实际进行增、删、改一条记录时都需要先把对应的undo日志记下来。
事务id为10的事务插入一条数据 事务30和事务50分别对这条数据进行修改操作 每次对记录进行改动都会记录一条undo日志每条undo日志也都有一个roll_pointer属性INSERT操作对应的undo日志没有该属性因为该记录并没有更早的版本可以将这些undo日志都连起来串成一个链表 对该记录每次更新后都会将旧值放到一条undo日志中就算是该记录的一个旧版本随着更新次数的增多所有的版本都会被roll_pointer属性连接成一个链表我们把这个链表称之为版本链版本链的头节点就是当前记录最新的值。另外每个版本中还包含生成该版本时对应的事务id。于是可以利用这个记录的版本链来控制并发事务访问相同记录的行为那么这种机制就被称之为多版本并发控制(Mulit-Version Concurrency Control MVCC)。
2、ReadView
ReadView中主要包含4个比较重要的内容m_ids表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。min_trx_id表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id也就是m_ids中的最小值。max_trx_id表示生成ReadView时系统中应该分配给下一个事务的id值。注意max_trx_id并不是m_ids中的最大值事务id是递增分配的。比方说现在有id为123这三个事务之后id为3的事务提交了。那么一个新的读事务在生成ReadView时m_ids就包括1和2min_trx_id的值就是1max_trx_id的值就是4。creator_trx_id表示生成该ReadView的事务的事务id。
2.1、使用读已提交解决脏读 此隔离级别的事务在每次查询开始时都会生成一个独立的ReadView。在MuSQL中读已提交和可重复的很大一个区别就是ReadView的生成时机不同。 假设现在表 table 中只有一条由事务id为10的事务插入的一条记录。读已提交 —— 每次读取数据前都生成一个ReadView 现在系统里有两个事务id分别为80、120的事务在执行。 第1次select的时间点 执行过程 在执行SELECT语句时会先生成一个ReadView ReadView的m_ids列表的内容就是[80, 120]min_trx_id为80max_trx_id为121。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列data的内容是 222该版本的trx_id值为80在m_ids列表内所以不符合可见性要求trx_id属性值在ReadView的min_trx_id和max_trx_id之间说明创建ReadView时生成该版本的事务还是活跃的该版本不可以被访问如果不在说明创建ReadView时生成该版本的事务已经被提交该版本可以被访问根据roll_pointer跳到下一个版本。 下一个版本的列data的内容是111该版本的trx_id值也为80也在m_ids列表内所以也不符合要求继续跳到下一个版本。下一个版本的列data的内容是xx该版本的trx_id值为10小于ReadView中的min_trx_id值所以这个版本是符合要求的最后返回给用户的版本就是这条列data为xx的记录。 所以有了这种机制就不会发生脏读问题因为会去判断活跃版本必须是不在活跃版本的才能用不可能读到没有commit的记录。 不可重复读问题 然后我们把事务id为80的事务提交一下然后再到事务id为120的事务中更新一下表table中data的记录。 最后版本链 第二次select 执行过程 在执行SELECT语句时会又会单独生成一个ReadView该ReadView信息如下 m_ids列表的内容就是[120]事务id为80的那个事务已经提交了所以再次生成快照时就没有它了min_trx_id为120max_trx_id为121。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列data的内容是bbb该版本的trx_id值为120在m_ids列表内所以不符合可见性要求根据roll_pointer跳到下一个版本。 下一个版本的列data的内容是aaa该版本的trx_id值为120也在m_ids列表内所以也不符合要求继续跳到下一个版本。 下一个版本的列name的内容是222该版本的trx_id值为80小于ReadView中的min_trx_id值120所以这个版本是符合要求的最后返回给用户的版本就是这条列name为222的记录。 2.2、使用可重复读级别解决不可重复读问题 在第一次读取数据时生成一个ReadView 对于使用REPEATABLE READ隔离级别的事务来说只会在第一次执行查询语句时生成一个ReadView之后的查询就不会重复生成了。 在上面的例子中 这个SELECE1的执行过程如下 在执行SELECT语句时会先生成一个ReadView ReadView的m_ids列表的内容就是[80, 120]min_trx_id为80max_trx_id为121。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列data的内容是222该版本的trx_id值为80在m_ids列表内所以不符合可见性要求trx_id属性值在ReadView的min_trx_id和max_trx_id之间说明创建ReadView时生成该版本的事务还是活跃的该版本不可以被访问如果不在说明创建ReadView时生成该版本的事务已经被提交该版本可以被访问根据roll_pointer跳到下一个版本。 下一个版本的列data的内容是111该版本的trx_id值也为80也在m_ids列表内所以也不符合要求继续跳到下一个版本。 下一个版本的列data的内容是xx该版本的trx_id值为60小于ReadView中的min_trx_id值所以这个版本是符合要求的最后返回给用户的版本就是这条列data为xx的记录。 之后我们把事务id为80的事务提交一下然后再到事务id为120的事务中更新一下表table中data的记录。 这个SELECE2的执行过程如下 因为当前事务的隔离级别为可重复读而之前在执行SELECE1时已经生成过ReadView了所以此时直接复用之前的ReadView之前的ReadView的m_ids列表的内容就是[80, 120]min_trx_id为80max_trx_id为121。 根据前面的分析返回的值还是xx。 也就是说两次SELECT查询得到的结果是重复的记录的列data值都是xx这就是可重复读的含义。
2.3、MVCC下的幻读现象和解决
表中只有一条事务10插入的数据 第一次select 在执行SELECT语句时会先生成一个ReadView m_ids列表的内容就是[80]min_trx_id为80max_trx_id为81。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列data的内容是xx版本的trx_id值为10可以被当前事务访问最后返回给用户的版本就是这条列data为xx的记录。
第二次select 因为当前事务的隔离级别为可重复读而之前在执行SELECE1时已经生成过ReadView了所以此时直接复用之前的ReadView m_ids列表的内容就是[80]min_trx_id为80max_trx_id为81。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列data的内容是222版本的trx_id值为120如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值表明生成该版本的事务在当前事务生成ReadView后才开启所以该版本不可以被当前事务访问。 最终最后返回给用户的版本还是这条列data为xx的记录。这是这种情况下不会出现幻读现象。
特殊幻读现象 此时第一次读是 没有数据第二次 出现一条数据 就是第一次读如果是空的情况且在自己事务中进行了该条数据的修改。
2.4、ReadView中的比较规则
1、如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同意味着当前事务在访问它自己修改过的记录所以该版本可以被当前事务访问。
2、如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值表明生成该版本的事务在当前事务生成ReadView前已经提交所以该版本可以被当前事务访问。
3、如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值表明生成该版本的事务在当前事务生成ReadView后才开启所以该版本不可以被当前事务访问。
4、如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间(min_trx_id trx_id max_trx_id)那就需要判断一下trx_id属性值是不是在m_ids列表中如果在说明创建ReadView时生成该版本的事务还是活跃的该版本不可以被访问如果不在说明创建ReadView时生成该版本的事务已经被提交该版本可以被访问。
2.5、总结 MVCCMulti-Version Concurrency Control 多版本并发控制进行普通的SEELCT查询时才生效。 它指的就是在使用读已提交、可重复读这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程这样子可以使不同事务的读-写、写-读操作并发执行从而提升系统性能。 读已提交、可重复读这两个隔离级别的一个很大不同就是生成ReadView的时机不同读已提交在每一次进行普通SELECT操作前都会生成一个ReadView而可重复读只在第一次进行普通SELECT操作前生成一个ReadView之后的查询操作都重复使用这个ReadView就好了从而基本上可以避免幻读现象就是第一次读如果ReadView是空的情况中的某些情况则避免不了。