【MySQL】事务(下)

文章目录

  • 1. 各个隔离级别的演示
    • 事务隔离级别 —— 读未提交
    • 事务隔离级别—— 读提交
    • 事务隔离级别 —— 可重复读
    • 事务隔离级别 —— 串行化
    • 脏读 不可重复读 幻读的理解
  • 2. MVCC机制
    • 读写
    • 3个记录隐藏列字段
    • undo日志
    • 模拟MVCC
    • read view 理论
  • 3. 读提交与 可重复读的区别
      • 两者本质区别

1. 各个隔离级别的演示

事务隔离级别 —— 读未提交

输入 select @@global.tx_isolation; 查询当前的隔离级别
发现 其隔离级别为 串行化


先将全局隔离级别 修改为 读未提交
再次查询发现 修改成功,全局隔离级别 已经被修改为 读未提交


在终端1中,启动事务后,插入王五的数据,此时在终端2中也可以查到王五的数据
再次在终端1的事务中 更新王五的名字为qwe, 此时终端2的事务中 依旧能查到 王五的名字已经修改为qwe

一个事务在执行中,读到另一个执行中的事务的更新 但是还没有commit的数据,这种现象叫做 脏读


事务隔离级别—— 读提交

将全局隔离级别 改为 读 提交


在终端1 启动事务后,插入 田七的数据到表中 ,此时在终端2启动事务的表中 是查询不到田七的数据
在终端1中再次修改id值为2的名字为liubei,此时在终端2中依旧是没有对id值为2的名字做出修改
当终端1的事务 进行 提交后 ,终端2中的事务才能查询到 表做出的修改数据

当一个事务,并未commit,就造成 同一个事务内,同样的读取,在不同的时间段,读取到不同的值
这种现象叫做 不可重复读


事务隔离级别 —— 可重复读

首先要保证终端1和终端2的全局隔离级别 和 会话隔离级别 都为 可重复读

输入 select @@global.tx_isolation; 查询当前会话的隔离级别
发现当前为 read -committed 表示 读提交


将会话的隔离级别 修改为 可重复读


查询当前全局隔离级别 也是 为 可重复读


启动事务后,在终端1中,插入王五的数据时,在终端2中,是是不见对应王五的数据的
终端1就算进行了提交,在终端2中也是看不见王五数据的


在终端2中,进行commit提交后,发现才可以查看到 account表中 修改的数据


可重复读对于删除 也是如此,当在终端1中 删除id值为2的数据时,终端2中是没有数据变化


只有当终端2进行提交,才可以看到终端1对表做出 的删除数据的操作


事务隔离级别 —— 串行化

保证mysql让所有的事务 进行串行化,就可以保证mysql 绝对的完整性
一个安全的方案,但并不是一个高效的方案


保证终端1和终端2的全局隔离级别 和 会话隔离级别都为 串行化

设置 全局隔离级别 修改为 串行化
并查看当前全局隔离级别


将会话隔离级别 修改为 串行化
并查看当前会话 隔离级别


在终端1中,当想进行删除id值为1的数据时,发现卡住了


在终端2中,当事务进行提交,终端1中的删除id值为1的数据 的操作 就可以正常生效了


脏读 不可重复读 幻读的理解


一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读

(如在终端1中插入数据,而在终端2中是可以查询到数据的存在的)


同一个事务内,同样的读取,在不同的时间段,读取到了不同的值,这种现象叫做不可重复读

(如在终端1中查询数据,数据A是属于 50-100 范围内的,并且已经检测到数据A存在于50-100范围内, 但终端2在检测后修改数据A的范围 在100 -200 ,就会导致 终端1中继续检测时,发现 数据A还会存在于100-200 范围内)


一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据
会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读
情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读

(少数的mysql版本 虽然在可重复读 情况下,但依旧无法避免 终端2 能够查询到终端1的数据
正常来说在 可重复读情况下,终端2是不可以接收到来自终端1的数据的)


可以发现 读未提交 是 会触发 脏读、不可重复读、幻读 的情况的,所以隔离级别很低
其次 是 读已提交是不会触发 脏读 ,但是会触发 不可重复读、幻读的情况的
可重复读 与 可串行化 都不会 触发 脏读 不可重复读 、幻读 的情况

2. MVCC机制

一个数据库在并发访问时,具体场景有:
读-读并发,不存在任何问题,也不需要并发控制(没有人修改)
写-写并发,有线程安全问题,可能会存在更新丢失的问题
读-写并发,有线程安全问题,可能会造成事务隔离问题,出现脏读、幻读、不可重复读问题


读写

多版本并发控制(MVCC) 是一种用来解决 读写冲突的无锁并发控制

事务一定是有先有后 到达的,如何区分事务的先后问题
每一个事务 都有自己的事务ID
可以根据事务ID的大小,来决定事务到来的先后顺序

mysqld 可能会面临处理多个事务的情况,事务也有自己的生命周期
(其生命周期指的是 其要被创建、投递到等待队列中、拿出来等待执行、执行错误进行回滚、执行完毕要被消除)
所以mysqld 要对多个事务进行管理,管理的本质是 先描述 在组织
就可以把 事务 看作 mysql中的一个结构体对象或者类对象,而事务ID是在结构体内部的


3个记录隐藏列字段

DB_TRX_ID : 6 byte 最近修改或插入的事务ID ,记录创建这条记录或最后一次修改该记录的事务ID
( 以插入举例,最近一次 插入记录的事务 是谁插入的,对应的事务ID是谁,把对应的事务ID放入表中)

DB_ROLL_PTR: 7byte ,回滚指针 指向这条记录的上一个版本

DB_ROW_ID: 6 byte 隐含的自增ID ,如果表中没有主键,InnoDB 会自动 以 DB_ROW_ID 产生一个聚簇索引


创建一张表 student,其中内部并不包含主键,只有一个不为空的name和不为空的age


将张三的数据 插入到 student表中


DB_TRX_ID 为 null ,说明没有事务进行插入、删除或者修改
DB_ROW_ID 为1 ,说明表中没有创建主键,所以使用隐含的主键
DB_ROLL_PTR 为null, 说明没有执行任何操作,找不到启动事务后的上一次操作


undo日志

mysql内有一大堆的日志缓冲区,就可以将其放入buffer pool中,被称为 undo log
undo log 是应用层 由mysql维护的一段内存缓冲区,用于保存日志数据


模拟MVCC

想要将上述创建好的student表中 张三数据做出修改, 事务10 通过使用 update 将张三 修改为 李四

msyql 判断要对事务进行修改,就需要先给 记录 加锁
修改前,需要先将记录拷贝到 undo log 中,此时undo log 中就有了一行副本数据


因为把老版本在 undo log 中保存了一份,所以在DB_ROLL_PTR 中填入对应老版本的地址 0xaa
该记录就指向了 undo log 中的历史版本
最终把 name 从张三 改到 李四
又因为 是事务10对表中数据做出修改,所以 对应的 DB_TRX_ID 变为10
当事务提交后,就在该记录下释放锁


如果又来了一个事务11,要把表中的记录 做出修改,把age 从 28 改为 30
msyql 判断要对事务进行修改,就需要先给 记录 加锁
修改前,需要先将记录拷贝到 undo log 中,此时undo log 中就又有了一行副本数据


因为把老版本在 undo log 中保存了一份,所以在DB_ROLL_PTR 中填入对应老版本的地址 0xbb
该记录就指向了 undo log 中的历史版本
又因为 是事务10对表中数据做出修改,所以 对应的 DB_TRX_ID 变为11、age 变为 30
当事务提交后,就在该记录下释放锁


最终形成一个多版本的数据,就称为 MVCC 多版本控制
把上述的一个一个的版本,称之为一个一个的快照


当前读:读取最近的记录
快照读:读取历史版本,不读取最新数据
增删改 都叫做当前读
select 有可能是当前读、也有可能是 快照读

读写并发:当使用upate对数据做修改时, 写 的是 当前最新的数据,而读的是 历史版本的数据
不会出现访问同一个的位置 ,就不用加锁,可以并发进行读写操作


串行化的 读写 访问的都是 当前数据,所以读写必须都加锁
若select 采用快照读,即读取历史版本的数据 ,是不受加锁限制的,就可以并发可以执行
既提高了效率,又为未来实现隔离性提供底层支持


read view 理论

read view 就是 事务进行快照读 操作的时候 产生的 读视图
在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照
记录并维护当前活跃事务的ID
(每个事务开启时,都会被分配一个ID,这个ID是递增的,所以最新事务,ID值越大)

read view 在mysql中就是一个类,本质是用来可见性判断的

当某个事务执行 快照读时,对该记录 创建一个read view 读视图,用它作为条件,用来判断当前事务能够看到那个版本的数据
,既可能是当前最新的数据,也有可能是 undo log 里面某个版本的数据


在read view类中 有四个重要字段
mids 表示 一张列表,用来维护read view 生成时刻,系统正在活跃的事务ID
(事务是并发的,当一个事务在运行时,其他事务也可能在运行,所以获取正在活跃的事务ID)

up_limit_id 表示 mids列表中 事务ID最小的ID
low_limit_id 表示 read view 生成时刻系统尚未分配的下一个事务ID,也就是目前已经出现的事务ID的最大值+1
creator_trx_id 表示 创建这个read view 的事务ID



若版本链某一条记录中的事务ID 与自己的creator_trx_id 相同
说明现在正在查看的记录,就是自己创建的,所以就应该看到对应的事务


up_limit_id 表示正在活跃的事务ID中最小的
若遍历对应的版本链时,发现对应的事务ID 比 我所能看到的最小的事务ID 还要小
说明 DB_TRX_ID 对应的事务早就已经 结束提交
所以我应该看到 该事务


low_limit_id 表示 read view 生成时刻系统尚未分配的下一个事务ID
若遍历版本链,发现所记录某一条的事务ID 比我自己事务中的 low_limit_id 还要大
说明 该事务 还没有跑起来


假设有 7 8 9 10 号事务ID,在快照前, 7 和 9 号事务ID 先提交了
所以 m_ids 中 就为 8 和 10 号 事务ID
所以快照到的事务ID 可以不连续
即 DB_TRX_id 不在 mid_s列表中,说明已经提交了,就可以看到
如果在,则说明该事务和自己的事务一样都是活跃事务,没有提交,就不应该看到


read view 是事务可见性的一个类,不是事务创建出来的时候,就会有read view
而是当这个事务(该事务已经存在), 首次进行快照读的时候,mysql 会形成 read view

3. 读提交与 可重复读的区别

RR (repeatable Read) 表示 可重复读

RC(Read Committed) 表示 读提交


select * from user lock in share mode 以加共享锁方式进行读取,对应的是当前读
若不加 lock in share mode 则为对照读


查询当前隔离级别 发现为 串行化


将隔离级别设置为可重复读


向user表中插入id值为1的数据
输入 select * from user 查看当前user表中的数据


由于select * from user 是快照读,读取的是历史版本的数据
所以即使当终端1将id值为1的数据 的age修改为18
终端2中 进行从查询 表中 id值为1的数据 的age 依旧为15

所以将其改成 select * from user lock in share mode , 此时就按照当前读
再次查询表中id值为1的数据的age 为18

假设终端1中的事务为 事务A ,终端2中的事务 为 事务B
事务B进行快照读时,mysql就已经形成了一个 read view
事务B 快照对象里面的值 认为 事务A 是跟它一块运行的
事务B 就认为 事务A 在自己的 mid_s 列表中,没有提交,就看不到


先在终端1进行修改age, 进行提交后再查询


此时 终端2才进行查询
则发现即使是快照读 ,表中数据也是修改后的,与 当前读 到的数据是相同的

假设终端1中的事务为 事务A ,终端2中的事务 为 事务B

由于事务B在 事务A进行操作时,并没有进行快照读,从而没有生成对应的 read view
只有到 事务A 进行提交后 , 事务B 才进行快照读 ,生成 read view
此时 事务B中 mid_s列表 中 不存在 事务A的值,说明 已经提交了 ,就可以看到了


先在终端1进行修改age, 进行提交后再查询


此时 终端2才进行查询
则发现即使是快照读 ,表中数据也是修改后的,与 当前读 到的数据是相同的

假设终端1中的事务为 事务A ,终端2中的事务 为 事务B

由于事务B在 事务A进行操作时,并没有进行快照读,从而没有生成对应的 read view
只有到 事务A 进行提交后 , 事务B 才进行快照读 ,生成 read view
此时 事务B中 mid_s列表 中 不存在 事务A的值,说明 已经提交了 ,就可以看到了

两者本质区别

RR (repeatable Read) 表示 可重复读

RC(Read Committed) 表示 读提交


由于read view 形成时机的不同,从而造成 RC、RR 级别下 快照读的结果的不同

RR级别下 的某个事务 的对某条记录的第一次快照读会创建 一个快照及 read view
将系统活跃的其他事务记录起来

只有当首次快照读时,才会产生 read view ,所以之后的快照读 使用的都是 同一个 read view ,对之后的修改不可见
(此时更新数据,全被放入 read view的mid_s列表中,说明没有提交 不可见)


在RC级别下, 事务中,每次快照读都会重新生成一个 快照 和 read view
所以一个终端中的事务 就可以看到另一个终端中的事务提交的更新

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/145077.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS分布式文件系统开发指导

分布式文件系统概述 分布式文件系统(hmdfs,HarmonyOS Distributed File System)提供跨设备的文件访问能力,适用于如下场景: 两台设备组网,用户可以利用一台设备上的编辑软件编辑另外一台设备上的文档。平板…

AI大模型的制作:RAG和向量数据库,分别是什么?

目录 一、什么是 AI 大模型 二、RAG 三、向量数据库 四、如何制作一个好的 AI 大模型 一、什么是 AI 大模型 AI大模型是指具有大规模参数和复杂结构的人工智能模型。传统的机器学习模型通常有限的参数量,而AI大模型则通过增加参数量和层数来提升模型的表达能力…

黑客泄露 3500 万条 LinkedIn 用户记录

被抓取的 LinkedIn 数据库分为两部分泄露:一部分包含 500 万条用户记录,第二部分包含 3500 万条记录。 LinkedIn 数据库保存了超过 3500 万用户的个人信息,被化名 USDoD 的黑客泄露。 该数据库在臭名昭著的网络犯罪和黑客平台 Breach Forum…

经纬恒润马来西亚工厂正式投入试运行

2023年11月,经纬恒润在中国境外的第一家工厂正式投入试运行。新工厂位于马来西亚,于2023年4月开始筹建,规划总产能500万个汽车电子控制器,主要用于生产新能源汽车电子产品,以满足国外客户日益增长的需求。 经纬恒润马来…

C语言从入门到精通之【字符串】

C语言没有专门用于储存字符串的变量类型,字符串都被储存在char类型的数组中。数组由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元中,每个单元储存一个字符,每个字符占1个字节。 数组末尾位置的字符\0。这是空字符&am…

Eclipse使用配置tomcat服务:部署找不到web.xml

问题:部署找不到web.xml及其他资源文件。只有lib和class 解决:将web.xml所在目录添加到部署配置里

设备数据如何为预测性维护提供支持

预测性维护是现代制造业中一种高效而受欢迎的维护策略,它能够帮助企业提前发现设备故障的早期迹象,并采取相应措施,从而避免生产线的停机和生产效率的下降。实施预测性维护的关键在于充分利用设备数据,通过数据的收集、处理和分析…

yolo如何画框、如何变换目标检测框的颜色和粗细、如何运行detect脚本

这段代码是一个使用YOLO模型进行目标检测的Python脚本。下面我将逐步解释脚本的主要部分,并提供一些关于超参数的使用方法。 1. 脚本结构 导入相关库设置配置参数加载YOLO模型运行目标检测处理检测结果显示或保存结果 2. 超参数说明 --weights: 指定YOLO模型的…

工业控制(ICS)学习笔记

目标:工业互联网安全的比赛 工控CTF之协议分析1——Modbus_ctf modbus-CSDN博客 常见的工控协议有:Modbus、MMS、IEC60870、MQTT、CoAP、COTP、IEC104、IEC61850、S7comm、OMRON等 不用看了,没太多技术含量,做了一会发现全得看答案…

敏捷开发工具有哪些?这款在线敏捷工具好评如潮!

随着软件开发的日渐复杂,敏捷开发方法已经成为当前软件开发的主流方式之一。敏捷开发是一种快速且灵活的软件开发方法,以快速响应需求变化和提供高质量软件为目标。在敏捷开发过程中,使用合适的敏捷工具能够更好地辅助开发团队进行协作和管理…

接口自动化测试(Python+Requests+Unittest)合集详解教程

(1)接口自动化测试的优缺点 优点: 测试复用性。维护成本相对UI自动化低一些。回归方便。可以运行更多更繁琐的测试。 自动化的一个明显的好处是可以在较少的时间内运行更多的测试。为什么UI自动化维护成本更高? 因为前端页面变…

小程序实现语音识别功能

不废话&#xff0c;直接上代码 <template><view><u-popupround"16" :show"recordShow" :close-on-click-overlay"false":safe-area-inset-bottom"false"close"close"open"open"><view clas…

直播推流与拉流简概

推流&#xff1a;将直播内容推送至服务器的过程 拉流&#xff1a;为服务器已有直播内容&#xff0c;用指定地址进行拉取的过程 在推流中&#xff0c;我们想要进行传输到服务端, 那么肯定要将数据使用传输协议进行封装&#xff0c;变成流数据。常用的流传输协议有哪几种呢? RT…

数字化转型时代,商业智能BI到底是什么?

据国际数据公司&#xff08;IDC&#xff09;预测&#xff0c;2025年时中国产生的数据量预计将达48.6ZB&#xff0c;在全球中的比例为27.8%。商业智能BI这一专为企业提供服务的数据类解决方案&#xff0c;仅2021年上半年在中国商业智能BI市场规模就达到了3.2亿美元&#xff0c;商…

19C进入数据库出现问号

问题情况如图所示&#xff1a; 解决方法&#xff1a; su - oracle echo "NLS_LANGAMERICAN_AMERICA.ZHS16GBK;export NLS_LANG" >> ~/.bash_profilesource ~/.bash_profileofile

解决 vue3 element 表格和图片预览样式有冲突

查看表格中的预览出现样式问题冲突 <el-image:src"${realSrc}"fit"cover":style"width:${realWidth};height:${realHeight};":preview-src-list"realSrcList":append-to-body"true"><template #error><div c…

微服务nacos实战入门

注册中心 在微服务架构中&#xff0c;注册中心是最核心的基础服务之一 主要涉及到三大角色&#xff1a; 服务提供者 ---生产者 服务消费者 服务发现与注册 它们之间的关系大致如下&#xff1a; 1.各个微服务在启动时&#xff0c;将自己的网络地址等信息注册到注册中心&#x…

基础课2——中国智能客服发展历程

智能客服的发展历程可以追溯到20世纪90年代&#xff0c;当时互联网刚刚兴起&#xff0c;企业开始意识到在线客户服务的重要性。最初的智能客服系统主要基于电话呼叫中心软件&#xff0c;客户可以通过电话与机器人进行交互&#xff0c;获取所需的信息和服务。 随着互联网的普及…

日常生活小技巧 -- Visual Studio Code 简单使用

讲一下 Visual Studio Code 简单使用&#xff0c;怕以后长时间不用忘记了。 资源管理器 快捷键 ctilshiftE 搜索 快捷键 ctilshiftF 全部折叠 区分大小写、全字匹配 替换、全部替换 切换搜索详细信息 例如排除.h 和 .bat文件 *.h;*.bat源代码管理 暂存更改、放弃更…
最新文章