文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【MySQL系列】MySQL的事务管理的学习(二)_ 再次理解隔离性

2023-09-30 07:19

关注

「前言」文章内容大致是MySQL事务管理,续上一篇。

「归属专栏」MySQL

「主页链接」个人主页

「笔者」枫叶先生(fy)

MySQL

目录

七、再次理解隔离性

7.1 数据库并发的场景有

数据库并发的场景有以下三种:

其中读-写并发是数据库当中最高频的场景,下面讨论的就是这个,读-读并发不存在任何问题,写-写并发不谈

7.2 多版本并发控制(MVCC)

多版本并发控制(Multi-Version Concurrency Control)是一种用来解决读-写冲突的无锁并发控制,主要依赖记录中的3个隐藏字段列、undo日志和Read View实现

MVCC为事务分配单向增长的事务ID,为每个修改保存一个版本,版本与事务ID关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题:

下面先介绍3个隐藏字段列、undo日志和Read View

7.3 三个隐藏字段列

数据库表中的每条记录都会有如下3个隐藏字段列:

补充

例如,有一个测试表

create table if not exists student(name varchar(11) not null,age int not null);

插入一条数据

insert into student (name, age) values ('张三', 28);

在这里插入图片描述
查询该表的数据
在这里插入图片描述
查出来的记录不仅包含name和age字段,还包含三个隐藏字段
在这里插入图片描述
说明

7.4 undo日志

undo log简单理解成就是 MySQL 中的一段内存缓冲区,用来保存日志数据的,必要时会将缓冲区中的数据刷新到磁盘

7.5 模拟MVCC

事务ID为10的事务

假设现在有一个事务ID为10的事务,要将刚才插入学生表中的记录的学生姓名“张三”改为“李四”:

现在又有一个事务11

现在又有一个事务11,对student表中记录进行修改(update):将age(28)改成age(38)

在这里插入图片描述

上面的一个一个版本,我们可以称之为一个一个的快照

insert和delete的记录如何维护版本链

上面已经谈了update,update可以形成版本链,那insert和delete呢?

select不会对数据做任何修改,所以,为select维护多版本,没有意义

select读取,是读取最新的版本呢?还是读取历史版本?

先说两个概念,当前读 VS 快照读:

事务在进行增删查改的时候,并不是都需要进行加锁保护:

而select查询时应该进行当前读还是快照读,则是由隔离级别决定的,在读未提交和串行化隔离级别下,进行的都是当前读,而在读提交和可重复读隔离级别下,既可能进行当前读也可能进行快照读

undo log中的版本链何时才会被清除?

如何保证,不同的事务,看到不同的内容呢?也就是如何实现隔离级别?

7.6 Read View

ReadView类的源码如下:

class ReadView {// 省略...private:trx_id_t m_low_limit_id;trx_id_t m_up_limit_id;trx_id_t m_creator_trx_id;ids_t m_ids;trx_id_t m_low_limit_no;bool m_closed;// 省略...};

上述四个成员说明:

m_ids; //一张列表(集合),用来维护Read View生成时刻,系统正活跃的事务IDm_up_limit_id; //记录m_ids列表中事务ID最小的IDm_low_limit_id; //ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1m_creator_trx_id //创建该ReadView的事务ID

由于事务ID是单向增长的,因此根据Read View中的m_up_limit_idm_low_limit_id,可以将事务ID分为三个部分:

ReadView就是一个对象,初始化一次之后就不再改变了(只初始化一次)

在这里插入图片描述

注意:事务ID不一定是连续的,比如事务ID10,15,16,17…

上述对应的隐藏字段:

对应的源码策略如下:

bool changes_visible(trx_id_t id, const table_name_t& name) const MY_ATTRIBUTE((warn_unused_result)){ut_ad(id > 0);//1、事务id小于m_up_limit_id(已提交)或事务id为创建该Read View的事务的id,则可见if (id < m_up_limit_id || id == m_creator_trx_id) {return(true);}check_trx_id_sanity(id, name);//2、事务id大于等于m_low_limit_id(生成Read View时还没有启动的事务),则不可见if (id >= m_low_limit_id) {return(false);}//3、事务id位于m_up_limit_id和m_low_limit_id之间,并且活跃事务id列表为空(即不在活跃列表中),则可见else if (m_ids.empty()) {return(true);}const ids_t::value_type* p = m_ids.data();//4、事务id位于m_up_limit_id和m_low_limit_id之间,如果在活跃事务id列表中则不可见,如果不在则可见return (!std::binary_search(p, p + m_ids.size(), id));}

注意Read View是一个可见性的一个类,并不是事务创建出来就有Read View,而是当这个事务(已经存在)进行快照读的时候,MySQL才会形成Read View(进行select的时候,会自动形成)

7.7 Read View理论验证

下面进行 Read View的理论验证,即 Read View的整体流程

假设当前有条记录
在这里插入图片描述
有四个事务并发进行对该记录进行操作,事务4先进行修改,事务4进行修改完成之后,事务2进行快照读
在这里插入图片描述

//事务2的 Read Viewm_ids;    // 1,3m_up_limit_id;   // 1m_low_limit_id;  // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务IDm_creator_trx_id // 2

此时版本链是:
在这里插入图片描述
只有事务4修改过该行记录,并在事务2执行快照读前,就提交了事务
在这里插入图片描述
事务2在快照读该行记录的时候,就会拿该行记录的DB_TRX_ID去跟m_up_limit_idm_low_limit_id和活跃事务ID列表(m_ids) 进行比较,判断当前事务2能看到该记录的版本

//事务2的 Read Viewm_ids;  // 1,3up_limit_id;     // 1low_limit_id;    // 4 + 1 = 5,原因:ReadView生成时刻,系统尚未分配的下一个事务IDcreator_trx_id   // 2//事务4提交的记录对应的事务IDDB_TRX_ID=4//比较步骤DB_TRX_ID(4< up_limit_id(1) ? 不小于,下一步DB_TRX_ID(4>= low_limit_id(5) ? 不大于,下一步m_ids.contains(DB_TRX_ID) ? 不包含,说明,事务4不在当前的活跃事务中//结论故,事务4的更改,应该看到所以事务2能读到的最新数据记录是事务4所提交的版本,而事务4提交的版本也是全局角度上最新的版本

八、RR与RC的本质区别

RR是可重复读的缩写,RC是读提交的缩写

我们之前的查询语句都是快照读,如果想进行当前读,执行下列语句:

-- 以加共享锁方式进行读取,对应的就是当前读select * from 表名字 lock in share mode; -- 当前读

实验1

启动两个终端,将隔离级别都设置为可重复读,并查看此时表中的数据
在这里插入图片描述
两个终端各自启动一个事务,在左终端中的事务操作之前,先让右终端中的事务查看一下表中的信息
在这里插入图片描述
左终端中的事务对表中的信息进行修改并提交,右终端中的事务看不到修改后的数据
在这里插入图片描述
左边终端提交事务;右边终端进行当前读,可以看到最新的数据

select * from account lock in share mode;

在这里插入图片描述

实验2(进行同样的操作,只是SQL语句执行顺序不同)

在这里插入图片描述
左终端中的事务对表中的信息进行修改并提交,然后再让右终端中的事务进行查看,这时右终端中的事务就直接看到了修改后的数据
在这里插入图片描述
右边终端进行当前读,可以看到刚才读取到的确实是最新的数据
在这里插入图片描述

实验对比

上面两次实验的唯一区别在于,右终端中的事务在左终端中的事务修改数据之前是否进行过快照读

实验一的操作流程:
在这里插入图片描述

实验2的操作流程:

事务B在事务A修改age前没有进行过快照读
在这里插入图片描述

结论

RR与RC的本质区别

正是Read View生成时机的不同,从而造成RC,RR级别下快照读的结果的不同

--------------------- END ----------------------

「 作者 」 枫叶先生「 更新 」 2023.9.10「 声明 」 余之才疏学浅,故所撰文疏漏难免,          或有谬误或不准确之处,敬请读者批评指正。

来源地址:https://blog.csdn.net/m0_64280701/article/details/132743279

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯