MySQL 核心模块揭秘 | 05 期 | 读事务和只读事务的变形记

事务都以读事务身份启动,读事务和只读事务会在需要时发生变化,它们会怎么变化?这是本文要回答的问题。

作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。

在这里插入图片描述

1. update、delete

后面小节的内容和 update、delete 有关,我们先简单介绍一下这两类 SQL 语句的执行流程。

以更新一条记录为例,update 语句的简化执行流程如下:

  • server 层要求 InnoDB 从表中读取一条记录。
  • InnoDB 返回记录之后,server 层判断这条记录是否匹配 where 条件。
  • 如果匹配,用 update 语句 set 子句中指定的各字段值,替换 InnoDB 返回记录的对应字段值。
  • 替换字段值得到完整记录之后,server 层触发 InnoDB 更新记录。

以删除一条记录为例,delete 语句的简化执行流程如下:

  • server 层要求 InnoDB 从表中读取一条记录。
  • InnoDB 返回记录之后,server 层判断这条记录是否匹配 where 条件。
  • 如果匹配,server 层触发 InnoDB 删除记录。

2. 读事务

上一期我们介绍过,事务真正启动于执行第一条 SQL 语句时,如果第一条 SQL 语句是 select、update、delete,事务会以读事务的身份启动。

读事务启动时,没有分配事务 ID 和回滚段,事务对象也没有加入到 trx_sys->rw_trx_list 链表。

根据我们使用 MySQL 的经验,以读事务身份启动的事务,不仅能正常执行改变(插入、更新、删除)表中数据的操作,还支持 MVCC、回滚。

对于启动时没有分配事务 ID 和回滚段的读事务来说,这是怎么做到的呢?

有一句话能够很好的回答这个问题,就是以发展的眼光看问题

以读事务身份启动的事务,并不意味着一直都是读事务,它可以在某些时间点变成读写事务

根据执行的第一条 SQL 语句不同,读事务变成读写事务的时间点可以分为两类:

第一类:第一条 SQL 语句是 update 或 delete。

在 update 或 delete 语句执行过程中,读事务就会变成读写事务。

发生变化的具体时间点,又取决于这两类 SQL 语句更新或删除记录的第一个表是什么类型。

如果第一个表是用户普通表,InnoDB 从表中读取一条记录之前,会给表加意向排他锁(IX)。

加意向排他锁时,如果以下三个条件成立,InnoDB 就会把这个事务变成读写事务:

  • 事务还没有为用户普通表分配回滚段。
  • 事务 ID 为 0,说明这个事务现在还是读事务。
  • 事务的只读标识 trx->read_only = false,说明这个事务可以变成读写事务。

读事务变成读写事务,InnoDB 主要做 3 件事:

  • 分配事务 ID。
  • 为用户普通表分配回滚段。
  • 把事务对象加入 trx_sys->rw_trx_list 链表。

如果第一个表是用户临时表,因为它的可见范围只限于创建这个表的数据库连接之内,其它数据库连接中执行的事务都看不到这个表,更不能改变表中的数据,所以,update、delete 语句改变用户临时表中的数据,不需要加意向排他锁。

读事务变成读写事务的操作会延迟到 server 层触发 InnoDB 更新或删除记录之后,InnoDB 执行更新或删除操作之前。

在这个时间节点,如果以下三个条件成立,InnoDB 就会把这个事务变成读写事务:

  • 事务已经启动了。
  • 事务 ID 为 0,说明这个事务现在还是读事务。
  • 事务的只读标识 trx->read_only = false,说明这个事务可以变成读写事务。

有一点需要说明,改变用户临时表的数据触发读事务变成读写事务,不会分配用户临时表回滚段,需要等到为某个用户临时表第一次写 Undo 日志时才分配。

第二类:第一条 SQL 语句是 select。

在 select 语句执行过程中,读事务不会变成读写事务;这条 SQL 语句执行完之后、事务提交之前,第一次执行 insert、update、delete 语句时,读事务才会变成读写事务。

一个读事务变成读写事务的操作,只会发生一次,发生变化的具体时间点,取决于最先碰到哪种 SQL 语句。

如果最先碰到 insert 语句,server 层准备好要插入的记录的每个字段之后,会触发 InnoDB 执行插入操作。

执行插入操作之前,如果以下三个条件成立,InnoDB 就会把这个事务变成读写事务:

  • 事务已经启动了。
  • 事务 ID 为 0,说明这个事务现在还是读事务。
  • 事务的只读标识 trx->read_only = false,说明这个事务可以变成读写事务。

如果最先碰到的是 update 或 delete 语句,读事务变成读写事务的具体时间点,参照第一类中关于用户普通表、用户临时表的介绍。

3. 只读事务

只读事务是读事务的特例,以 start transaction 开始一个事务时,如果包含了 read only 关键字,这个事务就是一个只读事务。例如:

start transaction read only

只读事务不能改变(插入、更新、删除)系统表、用户普通表的数据,但是能改变用户临时表的数据。

改变用户临时表的数据,同样需要为事务分配事务 ID,为用户临时表分配回滚段。根据只读事务执行的第一条 SQL 语句不同,这两个操作发生的时间点也可以分为两类。

第一类:第一条 SQL 语句是 update 或 delete。

在 update 或 delete 语句执行过程中,server 层触发 InnoDB 更新或删除记录之后,InnoDB 执行更新或删除操作之前,如果以下三个条件成立,InnoDB 就为这个事务分配事务 ID、为用户临时表分配回滚段:

  • 事务已经启动了。
  • 事务 ID 为 0。
  • 事务是个只读事务(trx->read_only = true)。

第二类:第一条 SQL 语句是 select。

在 select 语句执行过程中,不会分配事务 ID 和用户临时表的回滚段;这条 SQL 执行完之后、事务提交之前,第一次执行 insert、update、delete 语句时,才会执行这两个操作。

对于一个只读事务,这两个操作只会执行一次,执行的具体时间点,取决于最先碰到哪种 SQL 语句。

如果最先碰到 insert 语句,server 层准备好要插入的记录的每个字段之后,会触发 InnoDB 执行插入操作。

执行插入操作之前,如果以下三个条件成立,InnoDB 会为这个只读事务分配事务 ID、为用户临时表分配回滚段:

  • 事务已经启动了。
  • 事务 ID 为 0。
  • 事务是个只读事务(trx->read_only = true)。

如果最先碰到的是 update 或 delete 语句,执行这两个操作的具体时间点,参照第一类的介绍。

4. 总结

以读事务或只读事务身份启动的事务:

  • 如果执行的第一条 SQL 语句是 update 或 delete,在 SQL 语句执行过程中,读事务会变成读写事务,只读事务会分配事务 ID 和用户临时表的回滚段。
  • 如果执行的第一条 SQL 语句是 select,在后续第一次执行 insert、update、delete 三种语句的其中一种时,读事务会变成读写事务,只读事务会分配事务 ID 和用户临时表的回滚段。

读事务变成读写事务,InnoDB 主要做 3 件事:

  • 分配事务 ID。
  • 为用户普通表分配回滚段。
  • 把事务对象加入 trx_sys->rw_trx_list 链表。

本期问题:关于本期内容,如有问题,欢迎留言交流。

下期预告:MySQL 核心模块揭秘 | 06 期 | 事务提交之前,binlog 写到哪里?

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MATLAB源码-第130期】基于matlab的BPSK-ZF迫零均衡,对比均衡前后的误码率曲线以及理论曲线。

操作环境: MATLAB 2022a 1、算法描述 信道均衡是通信系统中的一项关键技术,其主要目的是减少或消除由于信道特性导致的信号失真。在数字通信中,尤其是在无线通信系统中,由于多径传播等原因,接收到的信号会受到严重的…

0131-2-关于事件捕获和冒泡

关于事件捕获和冒泡 DOM事件流分为三个阶段:捕获阶段、目标阶段、冒泡阶段 点击目标元素后,不会马上触发目标元素,而是先执行事件捕获,从顶部逐步到目标元素;处于目标阶段的时候触发目标元素;最后冒泡阶段…

java代码中调用自定义函数

定义函数 CREATE DEFINERrootlocalhost FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS float BEGINDECLARE SUM FLOAT DEFAULT 0;SET SUMnum1num2;RETURN SUM; END <select id"cunchu" resultType"java.util.Map">SELECT test_fun1(1,2) as r…

v-if及v-for、computed计算属性的使用

v-if 概念及使用 v-if是Vue.js中的一个指令&#xff0c;用于根据表达式的真假值条件性地渲染一块内容。如果表达式的值返回真&#xff0c;则Vue会渲染这块内容&#xff1b;如果返回假&#xff0c;则不渲染。 基本用法: <p v-if"isVisible">看到我了吗&#…

armbian ubuntu 小盒子安装nodejs npm vue3 环境

1.直接通过apt-get install nodejs 的版本太低了 我的是v12 我试了下 npm create vuelatest这种方式不行 所以就卸载了自动安装的nodejs apt remove nodejs 去淘宝的ftp上下载对应的版本 CNPM Binaries Mirror 我的小盒子是linux arm64版本 wget 之后解压 然后创建符号…

【C++】笔试训练(八)

目录 一、选择题二、编程题1、两种排序方法2、求最小公倍数 一、选择题 1、关于重载函数&#xff0c;哪个说明是正确的&#xff08;&#xff09; A 函数名相同&#xff0c;参数类型或个数不同 B 函数名相同&#xff0c;返回值类型不同 C 函数名相同&#xff0c;函数内部实现不…

LeetCode —— 17. 电话号码的字母组合

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

配置vite自动按需引入 vant 组件

为什么学 按需加载可以减少包体积,优化加载性能 学习内容 全局注册组件 import 需要的组件import 组件样式使用 app.use 注册组件 Tree Shaking 介绍使用 什么是 tree shaking&#xff1f; Tree shaking是一种优化技术&#xff0c;用于减少JavaScript或其他编程语言中未被使用…

EAS之WALT算法介绍

EAS调度器缘起 Linux内核的一直都使用完全公平调度器CFS(Completely Fair Scheduler)作为默认调度器&#xff0c;但是在使用中发现CFS如下几个问题。 1. CFS主要是为了服务器性能优先场景而设计的&#xff0c;主要目标是最大限度地提高系统的吞吐量&#xff0c;CFS调度的目标…

IDEA快捷键大全

提示&#xff1a; ① 主要记录我在使用 IDEA 开发的过程中用到的快捷键&#xff0c;可以提高开发速度。 ② 不一定要全部记住&#xff0c;主要是当一个参考文档&#xff0c;大家有一点印象&#xff0c;随时可以查看。 参考博客 > IntelliJ IDEA 快捷键说明大全&#xff08;官…

写静态页面——浮动练习

0、效果&#xff1a; 1、html代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>浮动…

漏洞原理XSS存贮型漏洞

漏洞原理XSS存贮型漏洞 XSS(跨站脚本攻击)是一种常见的Web安全漏洞,它允许攻击者将恶意代码注入到网页中,进而攻击用户的浏览器。存储型XSS漏洞是一种特定类型的XSS漏洞,它发生在Web应用程序中,其中用户输入的数据被存储在数据库或其他持久性存储中,并在页面重新加载时被…