• 十四、事务


    一、题目

    事务的特性、隔离级别、不同的隔离级别有什么问题、什么是幻读

    二、什么是事务

    事务是逻辑上的一组操作,要么都执行,要么都不执行。

    事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作就是:将小明的余额减少 1000 元,将小红的余额增加 1000 元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败

    二、事务的特性

    1. 原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
    2. 一致性(Consistency):执行事务后,数据库从一个正确的状态变化到另一个正确的状态;
    3. 隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
    4. 持久性(Durability):事务被提交之后。对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响;

    三、并发事务带来的问题

    在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。

    • 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是,依据"脏数据"所做的操作可能是不正确的
    • 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读
    • 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读
    • 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务 1 读取某表中的数据 A = 20,事务 2 也读取 A = 20,事务 1 修改 A = A - 1,事务 2 也修改 A = A - 1,最终结果 A = 19,事务 1 的修改被丢失

    不可重复度和幻读区别:不可重复读的重点是修改,幻读的重点在于新增或者删除

    例 1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务 1 中的 A 先生读取自己的工资为 1000 的操作还没完成,事务 2 中的 B 先生就修改了 A 的工资为 2000,导致 A 再读自己的工资时工资变为 2000;这就是不可重复读

    例 2(同样的条件, 第 1 次和第 2 次读出来的记录数不一样 ):假某工资单表中工资大于 3000 的有 4 人,事务 1 读取了所有工资大于 3000 的人,共查到 4 条记录,这时事务 2 又插入了一条工资大于 3000 的记录,事务 1 再次读取时查到的记录就变为了 5 条,这样就导致了幻读

    四、事务的隔离级别

    • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
    • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
    • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
    • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读
    隔离级别脏读不可重复读幻读
    READ-UNCOMMITTED
    READ-COMMITTED×
    REPEATABLE-READ××
    SERIALIZABLE×××

    MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过 SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改为 SELECT @@transaction_isolation;

    mysql> SELECT @@tx_isolation;
    +-----------------+
    | @@tx_isolation  |
    +-----------------+
    | REPEATABLE-READ |
    +-----------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    五、实际操作

    在下面我会使用 2 个命令行 MySQL,模拟多线程(多事务)对同一份数据的脏读问题。

    MySQL 命令行的默认配置中事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。如果要显式地开启一个事务需要使用命令:START TRANSACTION

    我们可以通过下面的命令来设置隔离级别

    SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
    
    • 1

    我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:

    • START TRANSACTION |BEGIN:显式地开启一个事务
    • COMMIT:提交事务,使得对数据库做的所有修改成为永久性
    • ROLLBACK:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改

    5.1、脏读(读未提交)

    在这里插入图片描述

    5.2、避免脏读(读已提交)

    在这里插入图片描述

    5.3、不可重复读

    还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,一个事务还没有结束,就发生了不可重复读问题
    在这里插入图片描述

    5.4、可重复读

    在这里插入图片描述

    5.5、幻读

    在这里插入图片描述
    SQL脚本 1 在第一次查询工资为 500 的记录时只有一条,SQL脚本 2 插入了一条工资为 500 的记录,提交之后;SQL脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读


    转载请标明出处,原文地址:https://blog.csdn.net/weixin_41835916 如果觉得本文对您有帮助,请点击支持一下,您的支持是我写作最大的动力,谢谢。
    这里写图片描述

  • 相关阅读:
    linux高级编程(IO多路复用)
    C++ API设计之风格
    【Educoder数据挖掘实训】异常值检测-值域法
    Scrum和Kanban方法的结合:Scrumban的实施指南
    内网-2(代理)
    【笔记】大话设计模式-11-13
    PIP安装本地离线包whl
    基于Python深度图生成3D点云
    MySql基础篇——存储过程和函数
    Salesforce震撼发布Einstein 1:下一代人工智能平台和智能对话助手!
  • 原文地址:https://blog.csdn.net/weixin_41835916/article/details/125917200