mysql 事务详解一

前言

提到事务,大家肯定不陌生。在我们现实生活中也是存在的,比如我们去超市购物,然后去支付。虽然是两个步骤,必须保证同时成功,这个交易才可以完成。

如果这个场景,拿到我们购物系统,就是几张表订单表、支付表、流水表。你往订单表插入一条数据,同时也会往支付表,流水表拆入一条数据,这个插入操作必须同时成功。这就是事务,简单来说事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在mysql 中,事务支持是在引擎层实现的。并不是所有的引擎都支持事务,比如说Innodb 支持而myisam不支持,这也是Innodb取代myisam的原因。

不仅mysql 支持事务,很多数据库 Mongodb也支持,虽然他们实现的方式不一样,我会在接下来的文章详细阐述。今天我们主要讲的是mysql 事务。

隔离性与隔离级别

一个数据系统支不支持事务,主要有四大特性决定的,ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。只要支持四大特性,我们就说系统支持事务。

大家要去了解这几个特性,首先必须明白mysql 的几种日志:redolog(重做日志),binlog(归档日志),undolog(回滚日志)

Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。是通过redolog和undolog实现的

Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。

Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。 是通过undolog 实现的

Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 是通过redlog 和 binlog 实现的

当数据库多个事物同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题。

脏读:读到其他事物未提交的数据

不可重复读:同一个事物前后读到的数据内容不一致

幻读:前后读取的记录数量不一致。也就是说感知到了其他事物对数据的insert,delete 操作

为啥会有那么多的问题,主要是于事物的隔离级别有关

事务有以下几种隔离级别:

读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。

读提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。

可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。

串行化(serializable):顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

读提交和可重复读比较难以理解,这两种隔离级别也是用的最多的。他们的实现都与一种技术(mvcc)有关,关于这个话题,我会在接下来的文章继续阐述。读提交他解决了脏读的问题,可重复度解决了事务的不可重复度的问题,同时它通过间隙锁解决了幻读的问题。其他的两种隔离级别都没有用到mvcc,读未提交会产生大量的脏数据,用的少。串行化性能太低,事务串行化执行,并发下的效率。接下来我们将通过例子详细阐述这几种隔离级别。

有这样一个表

mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);

读未提交

事务A事务B
启动事务 查询得到值1启动事务
查询得到值1
将1改成2
查询得到值V1=2
提交事务B
查询得到值v2=2
提交事务A
查询得到值v3=2

通过上面的例子可以看到事务B还没有提交,事务A就看到了结果

读提交

事务A事务B
启动事务 查询得到值1启动事务
查询得到值1
将1改成2
查询得到值V1=1
提交事务B
查询得到值v2=2
提交事务A
查询得到值v3=2

通过上面的例子可以看到事务B提交后,事务A就可以看到事务B提交的数据

可重复度

事务A事务B
启动事务 查询得到值1启动事务
查询得到值1
将1改成2
查询得到值V1=1
提交事务B
查询得到值v2=1
提交事务A
查询得到值v3=2

通过上面的例子可以事务在执行期间看到的数据前后必须是一致的。在事务A中v2和v1的数据和它查询的数据保持一致

串行化(serializable)

事务A事务B
启动事务 查询得到值1启动事务
查询得到值1
将1改成2
查询得到值V1=1
提交事务B
查询得到值v2=1
提交事务A
查询得到值v3=2

通过上面的例子:事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。也就是说事务A执行完了事务B才开始执行

在实现上,数据库会在读提交和可重复度隔离级别下创建一个视图,访问的时候以视图的逻辑结果为准。在可重复读隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,在每个sql 语句开始执行的时候创建的。读未提交每次都是返回记录最新的数据。串行化是用加锁的方式避免并发访问。

由此可见不同的隔离级别,数据库的行为是不同的。大家应该选择数据库合适的隔离级别。mysql 默认的隔离级别是可重复读,oracle 默认的隔离级别是读提交。不过现在很多厂把mysql 的隔离级别改成读提交,这是为了减少锁冲突,可重复读为了解决幻读引入了复杂的锁机制。

可以通过下列方式查看数据库的隔离级别

mysql> show variables like 'transaction_isolation';

ERROR 4031 (HY000): The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.

No connection. Trying to reconnect...

Connection id: 283

Current database: zipkin

+-----------------------+-----------------+

| Variable_name | Value |

+-----------------------+-----------------+

| transaction_isolation | REPEATABLE-READ |

+-----------------------+-----------------+

1 row in set (0.07 sec)

可重复读的隔离级别也不是没有人用,试想下面的场景:

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

这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

事务隔离的实现

在mysql 中,实际上每条记录在更新的时候都会记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。这些数据通过事务id记录在undolog中,这就是所谓的回滚日志

当前值是 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 的库。最终只好为了清理回滚段,重建整个库。除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库,这个我们会在后面讲锁的时候展开。

事务的启动方式

1、显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。这个时候事务并没有开始,事务的开始是它们之后的第一个操作 InnoDB 表的select 语句启动。如果想马上启动一个事物用start transaction with consistent snapshot这个命令

2、set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。因此,我会建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。

对于一个需要频繁使用事物的业务。我们可以用 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

这篇文章我们已经降到了事物,那么我们接下来思考几个问题:

1、使用长事务的弊病? 为什么使用常事务可能拖垮整个库?

1)长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

2)长事务更容易导致死锁,会进行大量的死锁检测,消耗大量cpu,影响系统性能。关于死锁的话题可以阅读mysql 锁详解-CSDN博客 这篇文章

3)容易造成超时,并使业务不断重试,使系统造成的很大的压力

4)会占用mysql 的连接,mysql 的连接得不到释放,会对业务的造成不好的影响

2、如何避免长事务的出现?

从数据库方面:

a.设置autocommit=1,不要设置为0。

b.写脚本监控information_schemal.innodb_trx表中数据内容,发现长事务,kill掉它。

c.配置SQL语句所能执行的最大运行时间,如果查过最大运行时间后,中断这个运行事情长的SQL语句。

d.设置回滚表空单独存放,便于回收表空间。

从业务代码方面:

a.确认是否使用了autocommit=0的配置,如果有关闭它,然后再业务代码中手动的使用begin;commit来操作。

b.检查业务逻辑代码,能拆分为小事务的不要用大事务。

c.检查代码,把没有必要的select语句被事务包裹的情况去掉。

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

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

相关文章

【kubernetes】kubeadm部署k8s集群(3主3从+keepalived/nginx负载均衡高可用)

目录 一、完成系统初始化 步骤一:常规环境初始化 步骤二:内核版本升级以及内核限制文件参数修改 步骤三:提前准备好负载均衡器和keepalived(接着之前的二进制部署修改的) 二、所有节点部署docker,以及指定版本的kubeadm 步骤…

大厂面试-美团高频考察算法之重排链表

本文学习目标或巩固的知识点 学习如何处理链表重排类题目 巩固反转链表巩固快慢指针巩固合并链表 提前说明:算法题目来自力扣、牛客等等途径 🟢表示简单 🟡表示中等 🔴表示困难 🤮表示恶心 博主真实经历,…

pikachu靶场-File Inclusion

介绍: File Inclusion(文件包含漏洞)概述 文件包含,是一个功能。在各种开发语言中都提供了内置的文件包含函数,其可以使开发人员在一个代码文件中直接包含(引入)另外一个代码文件。 比如 在PHP中,提供了&…

unity学习(40)——创建(create)角色脚本(panel)——UI

1.点击不同的头像按钮,分别选择职业1和职业2,create脚本中对应的函数。 2.调取inputfield中所输入的角色名(限制用户名长度为7字符),但愿逆向的服务器可以查重名: 3.点击头衔,显示选择的职业&a…

二手货wordpress企业网站主题模板

二手车wordpress主题模板 简洁的二手车wordpress主题模板,适合做二手车业务的公司官方网站使用。 https://www.jianzhanpress.com/?p3473 wordpress二手物资回收主题 绿色wordpress二手物资回收主题,用于二手物资回收公司WP建站使用。 https://www.…

算法【查找算法的概念】

查找算法概念 1、查找的基本概念2、评价查找算法3、问题: 查找过程中我们要研究什么? 1、查找的基本概念 查找的概念: 根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素或者记录。 查找算法也可以叫搜索算法。查找算法就是从一个有序…

HTMLElement.click()的回调触发踩坑

先看看以下代码 const el document.getElementById("btn") el.addEventListener("click", () > {Promise.resolve().then(() > console.log("microtask 1"));console.log("1"); }); el.addEventListener("click", (…

深度学习基础——U-Net图像分割

图像分割,就是根据图像的某种相似性特征(如亮度、颜色、纹理、面积、形状、位置、局部统计特征或频谱特征等)将医学图像划分为若干个互不相交的“连通”区域。 相关特征在同一区域内表现出一致性或相似性,而在不同区域间表现出明显的…

yolov8-seg dnn调用

接上篇一直更换torch、opencv版本都无法解决这个问题(seg调用dnn报错)。那问题会不会出在yolov8源码本身呢。yolov8的讨论区基本都看过了,我决定尝试在其前身yolov5的讨论区上找找我不信没人遇到这个问题。很快找到下面的讨论第一个帖子&…

八、线性代数二 ,矩阵的秩

目录 1、矩阵子式的定义与子式个数的计算: 2、矩阵秩的定义: 3、矩阵秩的计算方法: 4、矩阵秩的 性质: 线性代数四——几个重要的矩阵点积_线性代数 矩阵点积-CSDN博客 1、矩阵子式的定义与子式个数的计算: 概念&…

RocketMQ高性能核心原理与源码架构剖析

RocketMQ高性能核心原理与源码架构剖析 读、写队列 采用读写分离的方式,RocketMQ在创建Topic的时候会单独设置读队列和写队列,写队列负责写入以及同步数据到读队列,读队列会记录消费者的offset,负责消息拉取,通过Mes…

7-liunx服务器规范

目录 概况liunx日志liunx系统日志syslog函数openlog 可以改变syslog默认输出方式 ,进一步结构化 用户信息进程间的关系会话ps命令查看进程关系 系统资源限制改变工作目录和根目录服务器程序后台话 概况 liunx服务器上有很多细节需要注意 ,这些细节很重要…

openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议

文章目录 openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议 openGauss学习笔记-228 openGauss性能调优-系统调优-LLVM使用建议 目前LLVM在数据库内核侧已默认打开,用户可结合上述的分析进行配置,总体建议如下: 设置合理的wor…

谷歌seo推广有什么方式?

首先是网站优化,这是所有SEO工作的基础,这不仅仅意味着关键词的优化,还包括提升网站的加载速度、确保良好的移动设备适配性、以及加强网站的安全性,一个技术性能优异的网站,能够为用户提供更佳的体验,从而受…

【IDEA】安装Jrebel实现热部署

前言 devtool虽然也可以实现热部署 但是新增完方法和修改完参数后 热部署不生效 需要重启 而Jrebel却不用 功能也比devtool强大 但是收费 这里教大家怎么使用 插件下载 激活Jrebel

通俗易懂地理解稀疏性

今天我想与大家探讨的是一个数学和工程学中的重要概念——稀疏性。这个概念可能听起来很抽象,但它实际上贯穿于我们生活中的许多方面。那么,稀疏性到底是什么呢?简单来说,在数学和信号处理领域,一个信号被称为稀疏&…

2024年最值得尝试的创业项目,利用信息差,普通人下班也能做

大家好,我是电商花花。 到了2024年,人们依然在寻找长期可靠的副业项目,但我建议暂时停一下,因为抖音小店这个轻松暴利的副业项目还在等着我们呢。 抖音小店无货源创业项目作为一个轻资产创业项目,操作简单&#xff0…

基于springboot+vue的信息化在线教学平台(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

018—pandas 生成笛卡尔积排列组合合并多列字符串数据

思路: 本需求需要将给定的几列数据,生成一个排列组合形式的数据列,利用到 Pandas 多层索引生成的笛卡尔积的方法。 二、使用步骤 1.引入库 代码如下(示例): import pandas as pd2.读入数据 代码如下&…

每日一学—由面试题“Redis 是否为单线程”引发的思考

文章目录 📋 前言🌰 举个例子🎯 什么是 Redis(知识点补充)🎯 Redis 中的多线程🎯 I/O 多线程🎯 Redis 中的多进程📝 结论🎯书籍推荐🔥参与方式 &a…