您的位置:首页 > 教育 > 锐评 > 深圳微信网站开发_深圳品牌设计推荐_hao123上网从这里开始官方_个人网站seo入门

深圳微信网站开发_深圳品牌设计推荐_hao123上网从这里开始官方_个人网站seo入门

2025/4/19 7:01:44 来源:https://blog.csdn.net/qq_23095607/article/details/146782279  浏览:    关键词:深圳微信网站开发_深圳品牌设计推荐_hao123上网从这里开始官方_个人网站seo入门
深圳微信网站开发_深圳品牌设计推荐_hao123上网从这里开始官方_个人网站seo入门

参考资料:

参考视频(注意第二个视频关于幻读的讲解是错误的,详情见本文)

redoLog的结构详解

参考资料


学习内容:

1. MVCC要解决的问题

MVCC要解决的问题是,在不产生脏读等数据库问题的前提下,数据库的查询语句和更改语句不相互阻塞的情况;

在InnoDB中,MVCC仅仅存在于已提交读和可重复读两个隔离级别。

2. MVCC的实现机制

MVCC的实现完全依赖于undolog链表和ReadView两大板块

3. UndoLog链表

(1)InnoDB数据库中的每一行,都有三个隐藏字段

  1. 事务ID(DB_TRX」D):增删改都会默认开启事务,数据行每参与一次事务,就会更新改行的事务ID.
  2. 回滚指针():指向旧版本的数据
  3. Row_ID:  当InnoDB表没有规定主键,并且找不到非空列来构建聚簇索引,那么就会使用Row_ID作为改行的唯一标识,来构建聚簇索引

(2) Undo_Log的结构如下

        数据库中的数据,在参与事务前(修改前),都会记录一个undo_log(包括原先的回滚指针和事务ID)

        然后事务修改数据,并且更新隐藏的事务ID和回滚指针(回滚指针指向undo_log中的上一个版本数据)

        就这样不断地更新,就生成了undo_log版本链表

        其实undo_log版本链的结构要复杂的多,关于undo_log的详细介绍见前面的笔记

(3) 当前读和快照读

  1. 不加锁的select就是快照读(读取MVCC中undo_log的版本链中的数据)
  2. 加锁的select 和增删改等其他语句就是当前读(直接读取数据库表中的数据)

(4)Read view表

① ReadView作用

        当相同的数据被很多事务操作的时候,UndoLog就会变得错综复杂且冗长,那么在进行select快照读的时候,往往很难判断应该读取哪个快照;

        所以在进行select快照读的时候,会生成一个readview,用来帮助确定是需要读取哪个undoLog快照

②ReadView的结构

        ReadView其实是事务ID的集合,其中包括当前正在执行未提交的事务ID列表,创建ReadView的事务ID等

③ ReadView生成时机

        RC(已提交读):ReadView在RC(已提交读)隔离级别下,每进行一次select快照读,就会生成一个ReadView

        RR(可重复读): ReadView在RR(可重复读)隔离级别下,每一个事务只有一个readView,在第一次进行select快照读时生成,后续的快照读,共享这一份readView

④ ReadView的执行逻辑

        当我们进行select快照读时,就会使用ReadView,顺着当前数据以及它所连接的UndoLog版本链,进行事务ID的比对,选出对应的数据版本并返回;

        具体的对比逻辑是:

顺着当前数据以及UndoLog版本链往下找,

  1. 如果事务ID小于readView的事务ID列表中的最小值,表示该数据已提交,那么就进行返回;
  2. 如果事务ID大于readView的事务ID列表中的最大值,该数据不可以返回,继续寻找;
  3. 如果事务ID大于等于readView的事务ID列表中的最小值且小于等于事务ID列表中的最大值:
    1. 如果事务ID在readView的事务ID列表中,且事务ID等于创建readView的事务ID,那么就进行返回,否则不可以返回,继续寻找
    2. 如果事务ID不在readView的事务ID列表中,那么就进行返回;

⑤ InnoDb的MVCC在RR(可重复读)隔离级别下的幻读问题

结论:InnoDB在RR隔离级别下,仅仅解决了部分幻读问题,并没有解决全部

下面将通过举例来说明(数据库在RR隔离级别下)

假设数据库中有原始数据

1)发生幻读的情况

具体步骤如下:

 首先,事务202会进行一次select快照读,并生成ReadView

查询结果为:

然后事务201进行一次数据插入,并提交,此时的数据库为:

然后事务202进行了一次数据更新,这时就会产生UndoLog

最后事务202进行select快照读,因为此时隔离级别为RR(可重复读),所以共用着一份readView

readView会顺着数据和redoLog链进行查询

因为202属于区间[201,202],且202为当前事务ID,

所以查询到的数据为:

此时便发生了幻读

2) 解决幻读的情况

具体步骤如下:

  1. 首先,事务202会进行一次select快照读,并生成ReadView

查询结果为:

b.然后事务201进行一次数据插入,并提交,此时的数据库为:

 然后事务202进行了一次数据更新,这时就会产生UndoLog

  1. 最后事务202进行select快照读,因为此时隔离级别为RR(可重复读),所以共用着一份readView

e.readView会顺着数据和redoLog链进行查询
因为202属于区间[201,202],且202为当前事务ID,201虽然属于这个区间,但是不等于当前事务ID,所以只显示202的数据

所以得到的结果为:

并没有发生幻读


版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com