• MySQL - 事务四大特性、事务隔离级别、事务的脏读、不可重复读、幻读


    # 前言

    事务概念

    • 事务是一种逻辑处理机制,由一个有限的数据库操作序列构成。主要用于处理操作量大、复杂度高的数据。
    • MySQL 中,只有 Innodb 引擎才支持事务,作用于 insertupdatedelete 语句。

    为什么使用事务?

    场景举例: 提现功能、下单功能、充值功能等。

    本文提前准备工作

    1. 需要你连接 mysql 服务, 例: mysql -u root -p

    2. 提前创建一张用户表以及预设一些数据

      CREATE TABLE `user` (
        `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户的ID',
        `user_name` varchar(140) NOT NULL DEFAULT '0' COMMENT '姓名',
        `age` int(3) NOT NULL DEFAULT '0' COMMENT '年龄',
        `is_del` enum('YES','NO') DEFAULT 'NO',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表';
      
      INSERT INTO `user`(`id`, `user_name`, `age`, `is_del`) VALUES (1, 'Chon', 28, 'NO');
      INSERT INTO `user`(`id`, `user_name`, `age`, `is_del`) VALUES (2, 'Leslie', 18, 'NO');
      INSERT INTO `user`(`id`, `user_name`, `age`, `is_del`) VALUES (3, 'Sam', 38, 'NO');
      INSERT INTO `user`(`id`, `user_name`, `age`, `is_del`) VALUES (4, 'ALam', 48, 'NO');
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    一、事务的四大特性

    事务四大特性(ACID): 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

    1.1 原子性(Atomicity)

    原子性是指 事务作为整体被执行,是不可被分隔的单位,包含在其中的数据库语句,执行成功后,将执行结果持久化,如果发生错误,将会被 回滚 到事务开始前的状态,不可能停滞在中间某个环节或执行部分操作。

    场景举例: A 账户共有 1000元 人民币, 本次消费订单共计支付 200元 , 如果这时突然断电或服务器崩溃, 导致扣款成功但没有生成 订单信息, 这就发生了错误, 如果使用 事务 , 扣款与生成订单都成功时, 才算执行成功。


    1.2 一致性(Consistency)

    一致性指事务开始之前和完成以后,数据库的完整性约束没有被破坏。

    • 数据库字段要求为整型,不可能存进一个字母。
    • 假如你跟发小玩玻璃球,5 个人一共 100 个玻璃球,赢来输去,玩儿一下午,不考虑丢了,碎了,又去小卖部买等特殊情况,总是这 100 个玻璃球在手里转,不可能越玩儿越多,也不可能越玩儿越少,就是 100 个。

    1.3 隔离性(Isolation)

    隔离性指多个事务之间的执行是互不干扰的,一个事务不可能获取或操作到其它事务的内容

    • 但是 脏读 怎么来的,看本文下方的解释。

    1.4 持久性(Durability)

    持久性是指事务完成后,对数据库所作的更改会持久的保存在数据库之中,不会被回滚

    • 是不会被回滚,但 幻读不可重复读 怎么回事,看本文下方的解释。

    二、事务隔离级别

    隔离级别/影响脏读不可重复读幻读
    读未提交
    读已提交
    可重复读
    可串行化

    : 指在 特殊的操作流程中 会发生。

    : 指不会发生。


    2.1 命令查看或设置隔离级别

    2.1.1 查看默认全局事务隔离级别

    # 第一种方式:
    show global variables like '%isolation%';
    
    # 第二种方式:
    select @@global.tx_isolation;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.1.2 设置全局事务隔离级别

    # 设置为 读未提交
    set global transaction isolation level read uncommitted;
    
    # 设置为 读已提交
    set global transaction isolation level read committed;
    
    # 设置为 可重复读
    set global transaction isolation level repeatable read;
    
    # 设置为 可串行化
    set global transaction isolation level serializable;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.1.3 查看当前会话事务隔离级别

    # 第一种方式: 
    show session variables like '%isolation';
    
    # 第二种方式:
    select @@session.tx_isolation;
    
    # 第三种方式:
    select @@tx_isolation;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.1.4 设置当前会话事务隔离级别

    # 设置为 读未提交
    set session transaction isolation level read uncommitted;
    
    # 设置为 读已提交
    set session transaction isolation level read committed;
    
    # 设置为 可重复读
    set session transaction isolation level repeatable read;
    
    # 设置为 可串行化
    set session transaction isolation level serializable;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2 读未提交 (read uncommitted)

    读未提交: 查询语句不会加锁, 所有的事务都可以看到其他未提交事务的执行结果。


    读未提交可能会发生 脏读

    1. 事务1 获取到了 事务2 中未提交的数据,发生了 脏读

    2. 实例流程截图(请按照 红圈数字顺序 阅读):

      image-20220803142559309


    2.3 读已提交 (Read committed)

    读已提交: 当前事务加记录锁, 但不会在事务之间加间隙锁, 事务之间可以看到其他已提交事务的执行结果。

    1. 事务1 获取到了 事务2 中已提交的数据。

    2. 实例流程截图(请按照 红圈数字顺序 阅读):

      image-20220803150343395


    2.4 可重复读 (Repeatable read)

    可重复读: 是指多个事务并发读取时, 从事务的开始至结束, 本次事务内多次读取相同的数据, 都会返回一样的结果, 不会被其他事务的执行结果所影响。


    MySQL 默认隔离级别。


    可重复读解决了 脏读不可重复读 , 但可能会发生 幻读

    1. 事务1 无法获取 事务2 中未提交与已提交的数据。

    2. 实例流程截图(请按照 红圈数字顺序 阅读):

      image-20220803153750147


    2.5 可串行化 (Serializable)

    可串行化: 隐式将每个读语句加上共享锁, 通过强制事务排序, 使语句之间不会出现冲突。


    可串行化解决了 脏读不可重复读 幻读


    因为加锁, 所以可能出现锁竞争, 从而导致业务的超时。

    1. 事务1 先开启事务, 事务2 的 修改语句 得需要等待 事务1 提交后才会执行。

      image-20220803155756246

    2. 下图中可以看到, 事务1 提交后, 事务2 update 语句 在等待了 11.40 秒后, 才自动执行。

      image-20220803161223368


    三、事务之间的影响

    3.1 脏读

    简要说明: 一个事务中访问到了另一个事务中 未提交 的数据。


    使用 读已提交可重复读可串行化 的事务隔离级别, 可解决 脏读


    3.2 不可重复读

    简要说明: 同一个事务中, 读取相同条件的数据, 返回的结果不一致。


    使用 可重复读可串行化 的事务隔离级别, 可解决 不可重复读


    3.3 幻读

    简要说明: 同一个事务中, 读取相同条件的数据, 返回的条数不一致。


    使用 可串行化 的事务隔离级别, 可解决 幻读


    3.4 情况分析

    点我查看 - 可重复读隔离级别在哪种情况下会出现幻读

  • 相关阅读:
    内核调试环境:buildroot/debootstrap制作文件系统、编译内核、QEMU模拟
    springboot+vue+elementui外卖点餐系统骑手,商家
    嵌入式Linux—Framebuffer应用编程
    如何在谷某地球飞行模拟中导入简单飞机开发的飞机模型
    Spring MVC的执行流程
    rtf是什么格式的文件?rtf格式和word的区别是什么?
    利用Quartz设计采集系统并实现系统双活机制_在SpringCloud中自己设计系统双活---SpringCloud工作笔记178
    git 设置 upstream 上游代码库
    libevent库bufferevent事件实现socket通信
    wsl下jdk+wsl调试环境
  • 原文地址:https://blog.csdn.net/qq_35453862/article/details/126145656