Day867.事务隔离 -MySQL实战

news2024/9/25 3:24:38

事务隔离

Hi,我是阿昌,今天学习记录的是关于事务隔离的内容。

提到事务,肯定不陌生,和数据库打交道的时候,总是会用到事务。

最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱。转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,这 100 块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?这时就要用到“事务”这个概念了。简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的

MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如 MySQL 原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之一。


一、隔离性与隔离级别

提到事务,肯定会想到 ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),这次就来说说其中 I,也就是“隔离性”。

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。在谈隔离级别之前,首先要知道,隔离得越严实,效率就会越低

因此很多时候,都要在二者之间寻找一个平衡点。SQL 标准的事务隔离级别包括:

  • 读未提交(read uncommitted)
  • 读提交(read committed)
  • 可重复读(repeatable read)
  • 串行化(serializable )。

下面解释:

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

其中“读提交”和“可重复读”比较难理解,所以我用一个例子说明这几种隔离级别。

假设数据表 T 中只有一列,其中一行的值为 1,下面是按照时间顺序执行两个事务的行为。

mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(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> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name | Value |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+

总结来说,存在即合理,每种隔离级别都有自己的使用场景,要根据自己的业务情况来定。

那什么时候需要“可重复读”的场景呢?来看一个数据校对逻辑的案例。

假设在管理一个个人银行账户表。一个表存了账户余额,一个表存了账单明细。到了月底你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。这时候使用“可重复读”隔离级别就很方便。

事务启动时的视图可以认为是静态的,不受其他事务更新的影响。


二、事务隔离的实现

理解了事务的隔离级别,再来看看事务隔离具体是怎么实现的。这里展开说明“可重复读”。

在 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 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务

select * from information_schema.innodb_trx 
where TIME_TO_SEC(timediff(now(),trx_started))>60

四、总结

MySQL 的事务隔离级别的现象和实现,根据实现原理分析了长事务存在的风险,以及如何用正确的方式避免长事务。

现在知道了系统里面应该避免长事务,如果你是业务开发负责人同时也是数据库负责人,会有什么方案来避免出现或者处理这种情况呢?

  1. 通过information_schema.innodb_trx表监控事务的持续时间
  2. 增加undo表空间
  3. 通过配置参数max_execution_time指定事务执行的最长时间
  4. 利用pt工具监控长事务

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[前端笔记——CSS] 10.层叠与继承、选择器

[前端笔记——CSS] 10.层叠与继承、选择器1.层叠与继承1.1 冲突规则1.2 继承1.3 层叠1.4 CSS位置的影响2.选择器2.1 选择器是什么?2.2 选择器列表2.3 选择器的种类类型、类和 ID 选择器标签属性选择器伪类与伪元素运算符选择器参考表1.层叠与继承 1.1 冲突规则 CS…

一起自学SLAM算法:8.1 Gmapping算法

连载文章,长期更新,欢迎关注: 下面将从原理分析、源码解读和安装与运行这3个方面展开讲解Gmapping 算法。 8.1.1 Gmapping原理分析 首先要知道,Gmapping是一种基于粒子滤波的算法。在7.7.2节中已经提到过用RBPF(Rao-…

linux系统中使用QT实现APP开发的基本方法

大家好,今天主要和大家分享一下,如何使用QT进行APP的主界面开发的方法。 目录 第一:APP界面开发基本简介 第二:滑动界面实现 第三:APP界面开发实现 第四:APP主界面测试 第一:APP界面开发基本…

ARP渗透与攻防(一)之ARP原理

ARP原理 前言 ARP攻击就是通过伪造IP地址和MAC地址实现ARP欺骗,能够在网络中产生大量的ARP通信量使网络阻塞,攻击者只要持续不断的发出伪造的ARP响应包就能更改目标主机ARP缓存中的IP-MAC条目,造成网络中断或中间人攻击。ARP攻击主要是存在…

CSS3基础内容

目录 CSS基本样式 选择器分类 标签选择器 类选择器 利用类选择器画三个盒子 多类名 id选择器 id选择器和类选择器的区别 通配符选择器 CSS字体属性 字体粗细font-weight 字体样式 CSS文本属性 CSS的引入方式 行内样式表(行内式) 内部样式表…

2023年集卡活动简记

文章目录支付宝总评:【强烈推荐】年味浓,必中奖,单倍金额不算少。只关注开奖可以除夕当天玩儿。集卡分1.88元难度:【非常低】必中奖时间投入:【较少】无需打开其他App,比较轻松。操作体验:【好】…

深度理解卷积神经网络

神经网络包括卷积层,池化层,全连接层。一个最简单的神经元结构,假如有三个输入,都对应一个权重参数,然后通过权重加起来,经过一个激活函数,最后输出y。CNN中独特的结构就是卷积层,就…

拓展:阿里巴巴中文站架构演进分析【部分】

文章目录前言阿里巴巴中文站架构发展历程阿里巴巴第五代架构数据架构的复杂前言 由学习整理而来,并非有意抄袭。如果有冒犯行为,请及时联系作者进行处理! 阿里巴巴中文站架构发展历程 时间关键技术1999第一代网站架构Perl,CGl&…

【实操案例八】元组、集合操作 实例代码及运行效果图!

任务一:我的咖啡馆你做主 方法一:使用列表 # 任务一:我的咖啡馆你做主 # 方法一:使用列表lst[蓝山,卡布奇诺,拿铁,皇家咖啡,女王咖啡,美丽与哀愁]for i in lst:print(lst.index(i)1,.,i,end\t) print()while True:chice int(in…

SpringCloud+Ribbon 报错:java.net.unknownhostexception:XXX

SpringCloudRibbon 报错:java.net.unknownhostexception:XXX 问题分析: 网上很多的说法是依赖冲突导致,原因是什么呢:如果你的org.springframework.cloud:spring-cloud-starter-netflix-eureka-client 依赖中包含了ribbon依赖&…

常用JVM配置参数简介

既然学习JVM,阅读GC日志是处理Java虚拟机内存问题的基础技能,它只是一些人为确定的规则,没有太多技术含量。 既然如此,那么在IDE的控制台打印GC日志是必不可少的了。现在就告诉你怎么打印。 (1)如果你用的是…

Elasticsearch7.8.0版本高级查询—— 分页查询文档

目录一、初始化文档数据二、分页查询文档2.1、概述2.2、示例一、初始化文档数据 在 Postman 中,向 ES 服务器发 POST 请求 :http://localhost:9200/user/_doc/1,请求体内容为: { "name":"zhangsan", "ag…

数据分析-深度学习 Pytorch Day8

一。什么是循环神经网络:循环神经网络(Rerrent Neural Network, RNN),历史啊,谁发明的都不重要,说了你也记不住,你只要记住RNN是神经网络的一种,类似的还有深度神经网络DNN&#xff…

广州周立功CanTest卡使用教程一

网上有不少Can采集平台,包括Ardunio,Can卡,也有不少人用Freescale自己DIY一个平台,这些都是相当不错,并且都有成熟的代码,这里介绍在汽车诊断软件领域普遍都会选择的Can卡使用。 大家是不是对这个节面非常熟悉,CAN-bus 通用测试软件是一个专门用来对所有的 ZLGCAN 系列板…

【Python】基于经典网络架构训练图像分类模型——图像识别模型与训练策略(2023年1月22日,大年初一,春节快乐,兔年大吉)

声明:仅学习使用~ 今天是大年初一,祝大家新年快乐!!! 这个练习使用的图片稍多,因此初次在PyCharm里面可能会需要一些时间。 (注释中包含遇到的一些错误以及修正,同时也含有一些输出,部分较长的输出以省略号的形式在注释里面展示了) 2023.1.22,大年初一,新年快乐…

LoadBalancer源码解析

文章目录一、背景二、总体流程三、源码解析1. lb拦截器配置2. LB拦截器实现3. LB执行前置处理4. 负载均衡5. LB执行http请求一、背景 Spring Cloud 2020版本以后,默认移除了对Netflix的依赖,其中就包括Ribbon,官方默认推荐使用Spring Cloud …

生物化学 电阻抗成像OpenEIT 番外篇 EIT公式

EIT简介 摘要电阻抗断层扫描(EIT)是一种成像方式,使用无害的电流探测患者或物体。电流通过放置在靶表面上的电极馈送,数据由在电极处测量的电压组成,这些电压由一组线性独立的电流注入模式产生。EIT旨在恢复目标内部电…

【MySQL】第八部分 加密和解密函数

【MySQL】第八部分 加密和解密函数 文章目录【MySQL】第八部分 加密和解密函数8. 加密和解密函数总结8. 加密和解密函数 函数用法PASSWORD(str)返回字符串str的加密版本,41位长的字符串。加密结果不可逆,常用于用户的密码加密.( 8.0 版本以上不能用)MD5…

海湾化学冲刺上交所上市:计划募资30亿元,华融曾是其股东

近日,青岛海湾化学股份有限公司(下称“海湾化学”)预披露招股书,准备在上海证券交易所主板上市。本次冲刺上市,海湾化学计划募资30亿元,将于37.5万吨/年环氧氯丙烷绿色循环经济项目(一期&#x…

23种设计模式(十七)——状态模式【状态变化】

状态模式 文章目录 状态模式意图什么时候使用状态真实世界类比状态模式的实现状态模式的优缺点亦称:State 意图 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。 状态模式的解决思想是:当控制一个对象状态转…