MySQL实战解析底层---事务隔离:为什么你改了我还看不见
目录
前言
隔离性与隔离级别
事务隔离的实现
事务的启动方式
-
前言
- 和数据库打交道的时候,总是会用到事务
- 最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱
- 转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等
- 这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这 100 块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?
- 这时就要用到“事务”这个概念了
- 简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败
- 在 MySQL 中,事务支持是在引擎层实现的
- MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务
- 比如 MySQL 原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之一
- 下面将会以 InnoDB 为例,剖析 MySQL 在事务支持方面的特定实现,并基于原理给出相应的实践建议,希望这些案例能加深你对 MySQL 事务原理的理解
-
隔离性与隔离级别
- 提到事务,你肯定会想到 ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)
- 今天就来说说其中 I,也就是“隔离性”
- 当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念
- 在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低
- 因此很多时候,都要在二者之间寻找一个平衡点
- SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )
- 下面逐一解释:
- 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到
- 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到
- 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的;当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的
- 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”;当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
- 其中“读提交”和“可重复读”比较难理解,所以用一个例子说明这几种隔离级别
- 假设数据表 T 中只有一列,其中一行的值为 1
- 下面是按照时间顺序执行两个事务的行为
- 来看看在不同的隔离级别下,事务 A 会有哪些不同的返回结果,也就是图里面 V1、V2、V3 的返回值分别是什么
- 若隔离级别是“读未提交”
- 则 V1 的值就是 2
- 这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了
- 因此,V2、V3 也都是 2
- 若隔离级别是“读提交”
- 则 V1 是 1,V2 的值是 2
- 事务 B 的更新在提交后才能被 A 看到
- 所以, V3 的值也是 2
- 若隔离级别是“可重复读”
- 则 V1、V2 是 1,V3 是 2
- 之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的
- 若隔离级别是“串行化”
- 则在事务 B 执行“将 1 改成 2”的时候,会被锁住
- 直到事务 A 提交后,事务 B 才可以继续执行
- 所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2
- 在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准
- 在“可重复读”隔离级别下
- 这个视图是在事务启动时创建的,整个事务存在期间都用这个视图
- 在“读提交”隔离级别下
- 这个视图是在每个 SQL 语句开始执行的时候创建的
- 这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念
- 而“串行化”隔离级别下
- 直接用加锁的方式来避免并行访问
- 可以看到在不同的隔离级别下,数据库行为是有所不同的
- Oracle 数据库的默认隔离级别其实就是“读提交”
- 因此对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,你一定要记得将 MySQL 的隔离级别设置为“读提交”
- 配置的方式是,将启动参数 transaction-isolation 的值设置成 READ-COMMITTED
- 可以用 show variables 来查看当前的值
- 总结来说,存在即合理,每种隔离级别都有自己的使用场景,要根据自己的业务情况来定
- 那什么时候需要“可重复读”的场景呢?
- 来看一个数据校对逻辑的案例
- 假设你在管理一个个人银行账户表
- 一个表存了账户余额,一个表存了账单明细
- 到了月底你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致
- 你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果
- 这时候使用“可重复读”隔离级别就很方便
- 事务启动时的视图可以认为是静态的,不受其他事务更新的影响
-
事务隔离的实现
- 理解了事务的隔离级别,再来看看事务隔离具体是怎么实现的
- 这里展开说明“可重复读”
- 在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作
- 记录上的最新值,通过回滚操作,都可以得到前一个状态的值
- 假设一个值从 1 被按顺序改成了 2、3、4
- 当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view
- 在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)
- 对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到
- 同时你会发现,即使现在有另外一个事务正在将 4 改成 5,这个事务跟 read-view A、B、C对应的事务是不会冲突的
- 回滚日志总不能一直保留吧,什么时候删除呢?
- 答案是,在不需要的时候才删除
- 也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除
- 什么时候才不需要了呢?
- 就是当系统里没有比这个回滚日志更早的 read-view 的时候
- 基于上面的说明,来讨论一下为什么建议你尽量不要使用长事务
- 长事务意味着系统里面会存在很老的事务视图
- 由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间
- 在 MySQL 5.5 及以前的版本,回滚日志是跟数据字典一起放在 ibdata 文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小
- 有数据只有 20GB,而回滚段有 200GB的库
- 最终只好为了清理回滚段,重建整个库
- 除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库,这个会在后面讲锁的时候展开
-
事务的启动方式
- 如前面所述,长事务有这些潜在风险,建议尽量避免
- 其实很多时候业务开发并不是有意使用长事务,通常是由于误用所致
- MySQL 的事务启动方式有以下几种:
- (1)显式启动事务语句, begin 或 start transaction;配套的提交语句是 commit,回滚语句是 rollback
- (2)set autocommit=0,这个命令会将这个线程的自动提交关掉;意味着如果你只执行一个select 语句,这个事务就启动了,而且并不会自动提交;这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接
- 有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令
- 这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务
- 因此建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务
- 但是有的开发会纠结“多一次交互”的问题
- 对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次 “begin”,减少了语句的交互次数
- 如果你也有这个顾虑,建议你使用 commit work and chain 语法
- 在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务
- 如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销
- 同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中
- 可以在 information_schema 库的 innodb_trx 这个表中查询长事务
相关文章:

MySQL实战解析底层---事务隔离:为什么你改了我还看不见
目录 前言 隔离性与隔离级别 事务隔离的实现 事务的启动方式 前言 和数据库打交道的时候,总是会用到事务最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱转账过程具体到程序里会有一系列的操作࿰…...

变更数据捕获(CDC)
从广泛意义上说,全球许多企业每天都需要通过频繁的数据批量处理与加载,来定期将数据从一个数据库迁移到另一个数据库(或数据仓库)。这类定期批量加载的工作,往往既耗费时间,又会消耗原始系统的大量处理能力。因此,管理…...

【移动端表格组件】uniapp简单实现H5,小程序,APP多端兼容表格功能,复制即用,简单易懂【详细注释版本】
前言: 由于最近需要做移动端的项目 有个pc端的后台系统里面需要移一部分页面过来 而里面就有很多的表格,我就开始惯例网上先找前人栽的树,我好乘凉 然后找了一圈发现,不管是主流的移动端ui库或者网上自己写的帖子,或者…...

电子技术——CMOS 逻辑门电路
电子技术——CMOS 逻辑门电路 在本节我们介绍如何使用CMOS电路实现组合逻辑函数。在组合电路中,电路是瞬时发生的,也就是电路的输出之和当前的输入有关,并且电路是无记忆的也没有反馈。组合电路被大量的使用在当今的数字逻辑系统中。 晶体管…...

【C++】C++11 新特性
目录 1.列表初始化 1.1. C98中使用{}初始化的问题 1.2. 内置类型的列表初始化 1.3. 自定义类型的列表初始化 2. 变量类型推导 2.1. 为什么需要类型推导 2.2. decltype类型推导 2.2.1 为什么需要decltype 2.2.2. decltype 3. 对默认成员的控制(default、delete) 3.1. …...
JPA 相关注解说明
jpa相关注解 JPA(Java Persistence API)是一种Java规范,定义了一套标准的对象关系映射(ORM)API,用于将Java对象映射到关系型数据库中。JPA旨在统一各种ORM框架之间的差异,提供一种标准化的ORM解…...

SAP 生产订单/流程订单中日期的解释
SAP 生产订单/流程订单中日期的解释 基本开始日期:表示订单的开始日期 基本完成日期:表示订单的完成日期 我们在输入基本开始日期和基本完成日期时需要关注 调度 下面的“类型”,其中有向前、向后、当天日期等: 调度类型 为向前…...

Java设计模式笔记——七大设计原则
系列文章目录 第一章 Java 设计模式之七大设计原则 文章目录系列文章目录前言一、单一职责原则1.案例分析2.改进二、开闭原则1.案例分析2.改进三、里氏替换原则1.案例分析2.改进四、依赖倒转原则五、接口隔离原则1.案例分析2.改进六、合成复用原则1.案例分析2.改进七、迪米特原…...

记录第一次接口上线过程
新入职一家公司后,前三天一直在学习公司内部各种制度文化以及考试。 一直到第三天组长突然叫我过去,给了一个需求的思维导图,按照这个需求写这样一个接口, 其实还不错,不用自己去分析需求,按照这上面直接开…...

时序预测 | MATLAB实现Rmsprop算法优化LSTM长短期记忆神经网络时间序列多步预测(滚动预测未来,多指标,含验证Loss曲线)
时序预测 | MATLAB实现Rmsprop算法优化LSTM长短期记忆神经网络时间序列多步预测(滚动预测未来,多指标,含训练和验证Loss曲线) 目录 时序预测 | MATLAB实现Rmsprop算法优化LSTM长短期记忆神经网络时间序列多步预测(滚动预测未来,多指标,含训练和验证Loss曲线)效果一览基本描…...
如何利用Level2行情数据接口追板和交易股票?
十档行情看得更深的A股行情软件,我们在盘口数据中可以看到,买一到买五以及卖一到卖五,共10个价位的挂单情况,但基于上证所的level-2行情软件,视野则扩展到了买一到买十以及卖一到卖十数据,无疑比所有免费软…...
MySQL常用的聚合函数
聚合函数聚合函数对一组值进行运算,并返回单个值。也叫组合函数函数作用COUNT(*|列名) 统计查询结果的⾏数AVG(数值类型列名)求平均值,返回指定列数据的平均值SUM (数值类型列名)求和,返回指定列的总和MAX(列名)查询指定列的最⼤值MIN(列名)查…...

如何评估模糊测试工具-unibench的使用
unibench是一个用来评估模糊测试工具的benchmark。这个benchmark集成了20多个常用的测试程序,以及许多模糊测试工具。 这篇文章(https://zhuanlan.zhihu.com/p/421124258)对unibench进行了简单的介绍,本文就不再赘诉,…...

2023初级会计详细学习计划打卡表!自律逆袭,一次上岸!
2023年初级会计职称考试报名时间:2月7日-28日考试时间:5月13日—17日给大家整理了《经济法基础》和《初级会计实务》两科超实用的学习打卡表重要程度、难易度、易错点、要求掌握内容、章节估分等都全部总结在一起,一目了然!为什么…...

【Python】Python项目打包发布(四)(基于Nuitka打包PySide6项目)
Python项目打包发布汇总 【Python】Python项目打包发布(一)(基于Pyinstaller打包多目录项目) 【Python】Python项目打包发布(二)(基于Pyinstaller打包PyWebIO项目) 【Python】Pytho…...
一起Talk Android吧(第五百一十三回:Java中的byte数组与int变量相互转换)
文章目录整体思路示例代码各位看官们大家好,上一回中咱们说的例子是"自定义Dialog",这一回中咱们说的例子是" Java中的byte数组与int变量相互转换"。闲话休提,言归正转, 让我们一起Talk Android吧!在实际项目…...

22《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》中文分享
《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》 本人能力有限,如果错误欢迎批评指正。 第五章:Folding and Aggregation Are Cooperative Transitions (折叠和聚合是同时进行的) -蛋白质折叠的协同作…...

vue2 @hook 的解析与妙用
目录前言几种用法用法一 将放在多个生命周期的逻辑,统一到一个生命周期中用法二 监听子组件生命周期运行的情况运用场景场景一 许多时候,我们不得不在不同的生命周期中执行某些逻辑,并且这些逻辑会用到一些通用的变量,这些通用变量…...

网络技术|网络地址转换与IPv6|路由设计基础|4
对应讲义——p6 p7NAT例题例1解1例2解2例3解3例4解4一、IPv6地址用二进制格式表示128位的一个IPv6地址,按每16位为一个位段,划分为8个位段。若某个IPv6地址中出现多个连续的二进制0,可以通过压缩某个位段中的前导0来简化IPv6地址的表示。例如…...

MySQL运维知识
1 日志1.1 错误日志1.2 二进制日志查看二进制日志:mysqlbinlog ./binlog.000007purge master logs to binlog.000006reset mastershow variables like %binlog_expire_logs_seconds%默认二进制文件只存放30天,30天后会自动删除。1.3 查询日志1.4 慢查询日…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...