mysql 事务详解一

news2024/9/20 12:37:27

前言

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

如果这个场景,拿到我们购物系统,就是几张表订单表、支付表、流水表。你往订单表插入一条数据,同时也会往支付表,流水表拆入一条数据,这个插入操作必须同时成功。这就是事务,简单来说事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在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语句被事务包裹的情况去掉。

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

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

相关文章

智能高压森林应急消防泵|保障森林安全|深圳恒峰

随着科技的不断发展,我们的生活质量得到了显著提升。在森林保护领域,一项创新技术正在发挥着关键作用——智能高压森林应急消防泵。这种设备不仅提高了灭火效率,更为森林资源的安全保驾护航。 在过去,面对森林火灾,消防…

AIDL的工作原理与使用示例 跨进程通信 远程方法调用RPC

AIDL的介绍与使用 AIDL(Android Interface Definition Language)是Android中用于定义客户端和服务端之间通信接口的一种接口定义语言。它允许你定义客户端和服务的通信协议,用于在不同的进程间或同一进程的不同组件间进行数据传递。AIDL通过…

LDR6020芯片驱动未来:TYPE-C桌面显示器的新篇章

TYPE-C接口桌面显示器,与传统显示器截然不同。它不仅在视频传输方面表现出色,还融入了创新的充电功能。利用显示器的DC电源,可以轻松转换成PD协议,为笔记本、任天堂等HOST设备提供稳定的充电服务。 兼容性:连接无忧 …

redis GEO 类型原理及命令详解

目录 前言 一、GeoHash 的编码方法 二、Redis 操作GEO类型 前言 我们有一个需求是用户搜索附近的店铺,就是所谓的位置信息服务(Location-Based Service,LBS)的应用。这样的相关服务我们每天都在接触,用滴滴打车&am…

文件夹无法压缩是怎么回事?分享3种简单的方法~

在日常使用电脑的过程中,我们经常需要对文件夹进行压缩,以节省存储空间或方便传输。然而,有时候我们可能会遇到文件夹无法压缩的情况,这可能会让人感到困惑。本文将探讨文件夹无法压缩的原因,并提供解决方法&#xff0…

谷粒商城-nginx搭建域名访问环境性能压测

nginx搭建域名访问环境 正向代理与反向代理 正向代理:客户端向代理服务器发请求并指定目标服务器,代理向目标服务器转交请求并将获得的内容返回给客户端。 反向代理:用户直接访问反向代理服务器就可以获得目标服务器的资源。反向代理服务器…

基于EasyCVR视频汇聚系统的公安网视频联网共享视频云平台建设思路分析(二)

一、需求分析 随着科技的飞速发展,视频监控联网技术在公安工作中发挥着越来越重要的作用。为了提高公安部门对各类事件的响应速度和处理能力,建设一个高效、稳定的公安视频联网共享云平台显得尤为重要。通过建设开放的视频联网共享云平台,实…

Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】

有的自定义系统,对于自己外接的USB摄像头,android原生的camera和camera2都无法打开,CameraX也用不了。这时候就要用libusbCamera,这个库可以打开摄像头,还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目…

C语言第二十九弹---浮点数在内存中的存储

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 目录 1、浮点数在内存中的存储 1.1、练习 1.2、浮点数怎么转化为二进制 1.3、浮点数的存储 1.3.1、浮点数存的过程 1.3.2、浮点数取的过程 1.3、题目解析…

配置开机自启

进入任务计划程序 点击创建基本任务,按照向导一步一步进行下去

【数据结构】排序(1)

目录 一、概念: 二、直接插入排序: 三、希尔排序: 四、直接选择排序: 五、堆排序: 六、冒泡排序: 一、概念: 排序的概念: 使一串记录,按照其中的某个或某些关键字…

阿里巴巴店铺宝藏全揭秘:一键获取所有商品信息,电商业务效率飙升

阿里巴巴店铺所有商品API接口技术全解析 一、引言 在阿里巴巴这个全球领先的电商平台上,店铺所有商品API接口(item_search_shop)为开发者提供了一个便捷的途径,能够获取店铺的所有商品信息。通过这一接口,无论是数据…

PostgreSQL教程(十一):SQL语言(四)之数据类型

一、数值类型 数值类型由 2 字节、4 字节或 8 字节的整数以及 4 字节或 8 字节的浮点数和可选精度的十进制数组成。 下表列出了所有可用类型。 数值类型 名字存储长度描述范围smallint2 字节小范围整数-32768 到 32767integer4 字节常用的整数-2147483648 到 2147483647bigi…

【无标题】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘

项目场景: 做单链表反转题目,报错:member access within null pointer of type ‘struct ListNode’ 题目链接:LINK 问题描述 我明明在初始化指针时候,已经处理了n2->next情况却依然报错 这个报错提示含义是:大概就…

HTTPS(超文本传输安全协议)被恶意请求该如何处理。

HTTPS(超文本传输安全协议)端口攻击通常是指SSL握手中的一些攻击方式,比如SSL握手协商过程中的暴力破解、中间人攻击和SSL剥离攻击等。 攻击原理 攻击者控制受害者发送大量请求,利用压缩算法的机制猜测请求中的关键信息&#xf…

每天一个知识点 - 如何快速熟悉后端项目

入职一家新公司的时候,不可避免的就是接触到新公司的项目,有些项目一启动就是好几年,业务功能极其复杂,下面我总结几个方法让大家快速熟悉后端项目(图文结合) 用例图简析 用例是系统中的一个功能单元&…

顶级性能更有AI助力 RTX AI轻薄本竟强大如斯?华硕无畏Pro15 2024体验

不知觉,2024龙年腾飞之年俨然到来。回望这过去的一年里,我们的生活发生了很多变化🏮 有对身体健康的焦虑,也有对事业发展的迷茫,也时常回过头来反思自己在过去的一年里都有哪些不足、希冀在新的一年里努力改进自己&am…

Windows环境下查看磁盘层级占用空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Unity之ShaderGraph如何实现水面波浪

前言 这几天通过一个水的波浪数学公式,实现了一个波浪效果,感觉成就感满满,下面给大家分享一下 首先先给大家看一下公式; 把公式转为ShaderGraph 第一行公式:waveType = z*-1*Mathf.Cos(wave.WaveAngle/360*2*Mathf.PI)+x*Mathf.Sin(WaveAngle/360*-2*Mathf.PI) 转换…

基于JAVA的公司货物订单管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 客户管理模块2.2 商品维护模块2.3 供应商管理模块2.4 订单管理模块 三、系统展示四、核心代码4.1 查询供应商信息4.2 新增商品信息4.3 查询客户信息4.4 新增订单信息4.5 添加跟进子订单 五、免责说明 一、摘要 1.1 项目…