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 慢查询日…...
易基因-MeRIP-seq揭示衰老和神经变性过程中m6A RNA甲基化修饰的保守下调机制
大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。2023年02月22日,《美国国家科学院院刊》(Proc Natl Acad Sci USA)期刊发表了题为“Conserved reduction of m6A RNA modifications during aging and neurodegeneration is lin…...
暑期实习准备——Verilog手撕代码(持续更新中。。。
暑期实习准备——手撕代码牛客刷题笔记Verilog快速入门VL4 移位运算与乘法VL5 位拆分与运算VL6 多功能数据处理器VL8 使用generate…for语句简化代码VL9 使用子模块实现三输入数的大小比较VL11 4位数值比较器电路VL12 4bit超前进位加法器电路VL13 优先编码器电路①VL14 用优先编…...
Qt音视频开发19-vlc内核各种事件通知
一、前言 对于使用第三方的sdk库做开发,除了基本的操作函数接口外,还希望通过事件机制拿到消息通知,比如当前播放进度、音量值变化、静音变化、文件长度、播放结束等,有了这些才是完整的播放功能,在vlc中要拿到各种事…...
Linux基础命令-nice调整进程的优先级
文章目录 Nice 命令介绍 语法格式 常用参数 参考实例 1 调整bash的优先级为-10 2 调整脚本的优先级为6 3 调整指令的优先级 4 默认使用nice命令调整优先级 命令总结 Nice 命令介绍 nice命令的主要功能是用于调整进程的优先级,合理分配系统资源。Linux系…...
解析C语言strcmp()函数
函数名: strcmp 头文件: <string.h> 函数原型: int strcmp(const char *str1,const char *str2); 功 能: 比较两个字符串的大小,区分大小写 参 数: str1和str2为要比较的字符串 返回值: str1 > str2 , 返回 1&…...
初识scrapy
认识scrapyscrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需实现少量的代码,就能实现数据的快速抓取scrapy使用了Twisted异步网络架构,可以加快下载速度 pip install twisted安装:pip install s…...
(JUC)核心线程 和 救急线程的区别;Executors-固定大小线程池单线程线程池
核心线程 和 救急线程的区别 救急线程是有个生存时间的,它执行完任务了,过了一段时间,没有新任务了,救急线程就会销毁掉,变成结束的状态 核心线程没有生存时间,它执行完任务后,它仍然会被保存…...
vue2的动画和过渡效果
文章目录过渡 & 动画Transition 组件基于 CSS 的过渡效果CSS 过渡类名 class为过渡效果命名CSS 过渡 transition实例1:实例2:CSS 动画自定义过渡的类名同时使用 transition 和 animation深层级过渡与显式过渡时长性能考量JavaScript 动画可复用过渡效…...
正数负数的取反运算推导过程
取反题目题目:数据常用位十进制数据举例 我们计算a 60的取反运算c~a 求c 引用的知识点知识点: 正数的反码 补码 都一样。 0的补码反码都一样 负数的反码,最高是标记符号位,其他位置1变0 1变0 负数的补码 反码1 步骤斜体样式本篇我们全用8位二…...
C语言 条件编译
目录 1. #if #elif #else #endif 2. #ifdef #else #endif 3. #ifndef #else #endif 4. 三者区别 根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。 条件编译是预处理程序的功能,不是编译器的功能。 1. #if #elif #else #endif …...
网站建设 石景山/友链交换平台源码
scala包的引用: 1.包中有包 2.一个文件可以有多个包 3.如果包中的属性相同名称,而用的话为就近原则 package big.data.analyse.scala.classes/*** Created by zhen on 2018/9/15.*/ object Packages {def main(args: Array[String]) {val demo spark.navigation.test.Demo()v…...
怎么做招聘网站链接/苏州新闻今天最新消息新闻事件
修改/etc/security/limits.conf: * soft nofile 204800* hard nofile 204800 bugbugbugbugbugbug:虽说是全局修改,但是用systemctrl启动的进程,最大值还是1024 在搭建HAproxykeepalived遇到此问题 centos7还要修改 /etc/systemd/system.conf …...
网站建设-英九网络/竞价排名营销
有时候需要正无穷或负无穷来表示特殊情况,那正无穷和负无穷如何表示呢? 在C中, 如果是int,用INT_MAX表示正无穷,INT_MIN表示负无穷,需要包含头文件limits.h; 如果是double,用DBL_…...
建设b2c商城网站定/百度自助建站官网
第七章 开发向导 7.1 和ITK 的关系 大部分的elastix代码是基于ITK的。使用ITK意味着可以测试基类(图片类,存储分配)。自然ITK支持的图片格式elastix也支持。C源码可以在多种操作系统上使用多种编译器(最新版本VS2010࿰…...
新万网站建设/安卓优化大师hd
var files $(".profile-content").find("input[typefile]");files.each(function () {alert($(this).attr("data-id"));}) 转载于:https://www.cnblogs.com/firstcsharp/p/11291279.html...
新网站怎么让百度收录/关键词排名优化网站
1.2 重定向输出 本文讲的是C语言程序设计进阶教程一1.2 重定向输出,printf函数可能是人们写C程序时最先了解的几个函数之一。著名的“Hello World!”程序经常被用作给初学者的例子。在这个计算机程序中,文本被打印至终端。然而在一些场合中,…...