当前位置: 首页 > news >正文

【MySQL】事务的基本概念

目录

  • 事务是什么
    • 事务的回滚机制
  • 事务的ACID特性(重点)
    • 原子性 (Atomicity)
    • 一致性(Consistency)
    • 隔离性(Isolation)
    • 持久性(Durability)
  • 使用事务
    • 前提条件
    • 语法
    • 保存点
  • 事务的手动提交和自动提交
    • 手动提交
    • 自动提交
  • 事务的隔离性和隔离级别(重点)
    • 隔离性是什么
    • 为什么要有隔离级别
    • 查看和设置隔离级别
    • READ UNCOMMITTED - 读未提交与脏读
    • READ COMMITTED - 读已提交与不可重复读
    • REPEATABLE READ - 可重复读与幻读(MySQL默认隔离级别)
    • SERIALIZABLE - 串⾏化
  • navicate客户端注意

事务是什么

  • 事务就是把一组SQL语句打包成一个整体, 要么全部执行完成, 要么一条也不执行. 这组事务的SQL语句可以是一条, 也可以是多条.
    在这里插入图片描述
  • 在这个事务当中, 我们涉及到两条SQL语句
# ================更新操作===================
# 张三余额减少100
UPDATE bank_account set balance = balance - 100 where name = '张三';
# 李四余额增加100
UPDATE bank_account set balance = balance + 100 where name = '李四';
  • 这两条语句就可以打包成一个事务执行

事务的回滚机制

  • 在前面的例子中, 我们是说明了这两条SQL语句执行成功的情况. 但是由于各种原因, 有可能我们的事务也会执行失败. 比如说服务器突然崩溃, 断电, 会导致正在运行的事务停止, 发生异常. 那么在转账的例子中, 我们可能出现张三已经把钱转出去了, 张三的余额也变少了. 但是李四并没也收到转账, 那这个问题就大了.

  • 对于这种问题的出现, 我们MySQL就给出了回滚机制这个解决方案.

  • 在我们数据库运行的时候, 每次进行增/删/改涉及改动数据的操作的时候, 都会用一个日志, 把当前的操作记录下来.
    在这里插入图片描述

  • 当整个事务提交并完成的情况
    在这里插入图片描述

  • 当事务执行的过程中, 出现了异常情况, 我们就会对日志中做出的操作进行相反操作, 把增/删/改的数据恢复. 这就叫做回滚机制在这里插入图片描述

事务的ACID特性(重点)

原子性 (Atomicity)

  • 也就是我们上面说的事务要么全部执行, 要么一句也不执行. 但是通过上面的回滚机制( Rollback)了解到, 一句也不执行并非是真的一句也不执行, 而是事务执行过程中如果发生异常, 那么就会通过日志来恢复执行的操作来还原数据, 这样的效果就看起来是一句SQL语句也没有执行.

一致性(Consistency)

  • 总的来说就是事务执行前和执行后, 数据必须是合理的, 符合逻辑的.
  • 在执行前的总金额是800, 执行后的总金额也是800, 就算是事务的执行过程中发生了异常, 通过回滚机制也可以让数据恢复到执行事务前的状态, 所以事务的原子性对一致性也提供了保证. 这就是事务的一致性

在这里插入图片描述

隔离性(Isolation)

  • 数据库允许多个客户端对服务器发送事务执行, 服务器会进行并发处理(也就是一心二用, 同一时刻做多个事情), 但是就和人一样, 一旦同时处理的事情多了, 我们就可能会导致出错, 数据库也是如此, 如果同时执行的事情多了, 可能会导致数据出错, 不一致. 为了防止这个情况, 事务可以指定不同的隔离级别. 来解决这个问题.

持久性(Durability)

  • 事务处理结束后,对数据的修改将永久的写⼊硬盘,即便系统故障也不会丢失。

使用事务

前提条件

  • 要使⽤事务那么数据库就要⽀持事务,在MySQL中⽀持事务的存储引擎是InnoDB,可以通过
    show engines; 语句查看:

语法

在这里插入图片描述

  • 现在bank表中原本有两条数据, balance都是1000.0

在这里插入图片描述

  • 现在执行张三扣100, 李四加100, 在更新完后, 事务中查询的确是这样.
    在这里插入图片描述
  • 但是由于我们rollback(回滚), 就把我们刚刚的操作全部撤回. 数据就恢复当事务执行前的状态.
    在这里插入图片描述

保存点

  • 语法:SAVEPOINT sp1; – 创建一个名为 sp1 的保存点
  • 回滚到保存点语法: ROLLBACK TO SAVEPOINT savepoint_name;
  • 保存点就像我们打游戏的存档功能一样, 比如说我们大黑猴子到了打那个大头娃娃的哪里, 突然你要出去办点事情, 就可以存档你的游戏进度到大头娃娃哪里去了, 等你事情办完了可以回来打开这个存档继续从这个进度开始打, 如果你没有进行存档, 那么游戏进度自动清0了, 你就又得从新来一遍. 这就很反人性了.
  • 所以我们数据库的回滚机制也是一样的, 如果我确保前面的事务执行一切正常, 我们可以回滚到判定出异常的那一部分. 而不用让事务从头开始执行.
  • 这里我们返回到第二个保存点就是已经插入了王五哪里, 后面的赵六没有插入, 那么事务也就没有插入赵六.
    在这里插入图片描述

事务的手动提交和自动提交

手动提交

在这里插入图片描述

  • • ⼿动提交模式下,不⽤显⽰开启事务,执⾏修改操作后,提交或回滚事务时直接使⽤ commit
    或 rollback
  • 已提交的事务不能回滚

自动提交

在这里插入图片描述

  • 我们之前的单句执行的SQL语句就是自动提交的.

事务的隔离性和隔离级别(重点)

隔离性是什么

  • 在前面的ACID特性中我们的第三个特性就是隔离性, 总的来说就是我们很多时候在多个客户端向一个MySQL服务器提交事务, 数据库就会采用并发的处理方式来处理这些事务, 而我们前面说了, 并发操作就是一心二用, 在事情多了的时候, 是很可能会把数据搞错的. 所以我们MySQL提出了隔离级别来解决这种情况. 但是我们不同的隔离级别, 对多个事务, 有着不同的隔离效果, 也就是不完全隔离和完全隔离.

为什么要有隔离级别

  • 可能有人会有疑问, 为什么知道并发可能会导致数据出错还不完全隔离. 而是让程序员自己选择隔离级别到底完全隔离还是不完全隔离. 这就要从我们的不同业务场景来说了
  • 有的业务追求效率, 有的业务追求准确性.
  • 比如我们抖音点赞, 我们可以看到评论区的点赞数是没有给出一个准确的数字的. 通常是看2.2w, 3.3w什么的整体数字, 因为我们点赞是要求我们用户点了那个爱心, 就立马变红表示我们点赞了, 让用户立马得到反馈. 而不是让用户等个1, 2秒吧, 这就是追求效率的场景.
  • 再看我们银行转账, 我们银行转账的时候都是给我们客户说, 最多2个小时之内可以得到转账, 这个时候我们银行就是放弃了效率, 宁愿多花费一些时间, 把转账的数据搞对, 我们转出去多少钱, 别人就收到多少钱, 避免出现转出去别人没收到钱等情况, 这就是追求准确率的场景.

总结一下:

  1. 隔离级别越高. 并发越弱; 效率越低, 准确率越高.
  2. 隔离级别越低, 并发越强, 效率越高, 准确率越低.
  3. 我们要根据不同的业务场景来选择隔离级别.

查看和设置隔离级别

  • 事务的隔离级别分为全局作⽤域和会话作⽤域,查看不同作⽤域事务的隔离级别,可以使⽤以下的
    ⽅式:
# 全局作⽤域
SELECT @@GLOBAL.transaction_isolation;
# 会话作⽤域
SELECT @@SESSION.transaction_isolation;
  • 会话作用域只对当前客户端生效, 而全局作用域是多个客户端生效.
# ⽰例
# 设置全局事务隔离级别为串⾏化,后续所有事务⽣效,不影响当前事务
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# 设置会话事务隔离级别为串⾏化,当前会话后续的所有事务⽣效,不影响当前事务,可以在任何时候
执⾏
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

READ UNCOMMITTED - 读未提交与脏读

  • 这个隔离级别, 对两个事务执行的顺序没有做出任何的干预
  • 这个时候就会出现一个错误就是脏读, 脏读就指的就是事务A未提交的情况下, 事务B直接去读取事务A的数据. 那么这个时候事务A如果发生回滚或异常, 就会把数据还原回去. 这个时候事务B读取的事务A数据就是事务A还原之前的数据, 这个时候由于事务A还原了数据, 被事务B读取的还原之前的数据就是脏数据.
  • 事务A, 可以看到我们原始数据两个都是1000, 现在执行事务A张三向李四转账500, 这个时候事务A还没提交
    在这里插入图片描述
  • 事务B: 可以看到我们现在事务B读取的就是事务A转账后的数据.
    在这里插入图片描述
  • 事务A: 这个时候事务A由于某种原因回滚了, 撤销了转账的数据. 这个时候数据就变回了转账之前的数据, 两个都是1000
    在这里插入图片描述
  • 那么这个时候事务B就成小丑了, 好不容易读取了数据事务A又还原回去了, 读到的这个数据就是一个脏数据.
  • 这个脏读就像我高中班上的一个b哥一样, 有一次月考, b哥偷偷溜进了办公室看了自己的成绩. 一看自己数学140, 给b哥高兴坏了, 跑回来给我们说他数学考了140, 结果后来老师再次审核成绩的时候, 发现b哥的试卷改错了, 重新改一遍下来只剩下80分了, 然后公布成绩的那一天, 我看见b哥的表情是无法形容的.

READ COMMITTED - 读已提交与不可重复读

  • 为了解决脏读的这个问题, 我们就把隔离级别设置成读已提交的. 这个时候就解决了脏读的问题.

  • 不可重复读就是假设有事务A, 事务B, 事务C, 事务A把数据修改后, 提交了. 事务C读取第一次是事务A修改后的数据, 事务B又把同一个数据修改了. 提交了. 这个时候事务C第二次读取同一个数据读取到的就是事务B修改后的数据. 结果事务C两次读取同一个数据, 都不一样. 这就是不可重复读.

  • 事务A: 修改张三的余额, 加上300. 并且事务A提交
    在这里插入图片描述

  • 事务C读取事务A提交后张三的数据. 发现是1300
    在这里插入图片描述

  • 事务B, 把张三的数据再增加100, 并且提交.
    在这里插入图片描述

  • 事务C, 第二次查询张三的数据, 结果发现和第一次不一样, 是1400
    在这里插入图片描述

  • 这就是不可重复读的问题, 在同一个事务内读同一个数据结果两次不一样. 就如同有一天我姐姐, 上午还给我笑嘻嘻的说老弟今天中午想吃什么, 姐姐给你做. 晚上我和我姐姐说我想吃火锅, 姐姐就不耐烦给我说: 吃什么吃, 找你妈去. 这就让人有点接受不了这个落差了, 事务也是一样的.

REPEATABLE READ - 可重复读与幻读(MySQL默认隔离级别)

  • 为了解决不可重复读问题,可以把事务的隔离级别设置为 REPEATABLE READ这时同⼀个事
    务中读取的数据在任何时候都是相同的结果,但还会出现⼀个问题,事务A第一次查询的时候得到一个结果集, 事务B趁着这个空隙插入了数据, 这个时候事务A第二次查询的时候得到的结果集就出现了事务B插入的数据, 导致同一个事务内查询的第一次和第二次的结果集不一样
  • 事务A第一次查询的结果集只有两条记录
    在这里插入图片描述
  • 事务B趁着事务A还没结束提交, 插入了一条数据
    在这里插入图片描述
  • 事务A第二次查询, 还是两条数据. 根据我们上面说的, 这里应该是3条数据才对. 第一次结果集和第二次结果集的数据不一样. 可是这里还是两条数据,说明我们的REPEATABLE READ隔离级别已经处理了大部分的幻读情况了.
    在这里插入图片描述
  • 这里我们改变策略, 虽然我们查询出来的结果集王五并没有存在, 这个时候我们插入同一个王五的记录进去, 可以看到由于主键约束(主键列不能重复且不能为空), 数据库提示我们这条记录已经存在. 不能进行插入, 所以实际上还是存在幻读的.
    在这里插入图片描述

SERIALIZABLE - 串⾏化

  • 这个隔离级别就是完全解决了幻读的问题, 我们幻读之所以导致结果集不一样, 根本原因就是事务A和事务B同时开启, 事务B同一时刻插入了数据.这个隔离级别, 只能一个事务执行完了, 另一个事务才能执行
    在这里插入图片描述

  • 事务A第一次查询结果集是这样, 我们插入了主键列为20的赵六.
    在这里插入图片描述

  • 这个时候我们开启事务B插入主键列一样的值20, 名字为赵六的进去 正常来说, 我们的下方会说插入成功, 影响了1行, 这里却没有说, 说明这个事务并没有真正去执行并提交
    在这里插入图片描述

  • 事务A: 第二次查询同样的结果, 并没有出现幻读这种不同结果集情况. 这里我们进行提交事务, 事务A完成
    在这里插入图片描述

  • 事务B: 事务A完成后, 我们返回到事务B, 可以看到我们插入失败了(因为主键列值一样插入失败), 并且我们下面查询时间说用来29秒, 这就是事务B等待了29秒, 说明我们事务B是等待事务A执行提交(事务A花了29秒), 才开始执行的.
    在这里插入图片描述

从上面的例子上知道, 我们事务是完全隔离的, 事务A执行完了, 事务B才执行.

navicate客户端注意

  • 我们在这个客户端设置隔离级别的时候, 如果有多个客户端(连接), 在客户端A设置了隔离级别. 则要把客户端B关闭, 重新连接, 客户端B的隔离级别才生效
http://www.dtcms.com/a/323673.html

相关文章:

  • 智慧物流仓储分拣:陌讯多模态识别方案让准确率↑29.3% 实战解析
  • js零基础入门
  • 零基础-动手学深度学习-10.1. 注意力提示
  • vs2022编译Activemq
  • AnyDesk远程工具免费版,v9.5.110绿色便携版,秒连远程桌面,剪贴板同步超实用
  • 网络管理实战
  • B.10.01.6-DDD领域驱动设计:从理论到落地的完整指南
  • 【LLM实战|langgraph】langgrpah基础
  • WD5030A 芯片,24V降12V,输出电流15A,高度集成实现高效能与低成本的完美平衡
  • 如何免费配置各类AI API_Key?(附接入后测试)
  • 创建一个django项目
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(15):文法+单词第5回
  • 生产环境某业务服务JVM调优总结
  • DAY35打卡
  • [IOMMU]面向芯片/SoC验证工程的IOMMU全景速览
  • FMS 2025存储峰会获奖技术全景解读
  • 【linux基础】Linux命令提示符解析与操作指南
  • c++ 容器vector基础
  • 北斗变形监测技术应用与案例解析
  • RK3568 U盘/TF卡镜像更新
  • Mysql笔记-系统变量\用户变量管理
  • 学习嵌入式第二十四天
  • 【Python 语法糖小火锅 · 第 1 涮】
  • Vulnhub----Beelzebub靶场
  • 每周算法思考:栈与队列
  • 使用lightGCN完整训练用户 + 商品向量的 3 步指南
  • 在JVM调优时,你关注哪些指标?
  • 裸露土堆识别准确率↑32%:陌讯多模态融合算法实战解析
  • 20250808组题总结
  • C++11中的移动语义