• 【MySQL】——事务的基本概念


    • 💂 个人主页:努力学习的少年
    • 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
    • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦

    一. 事务的概念

    在MySQL环境中,事务是由一个单元的一个或多个SQL语句组成,这个单元的每个SQL语句是相互依赖的,而且单元作为一个整体是不可分割的。如果单元中的一个语句不能完成,整个单元就会回滚(撤销),所有影响到数据将返回到事务开始以前的状态,因此,只有事务中所有SQL语句执行成功,则才能说明这个事务被成功执行。使用一个简单的例子来理解事务:

    向公司添加一名新员工,这个过程由3个基本步骤组成(如图所示):

    • 在员工数据库中为员工创建一条新记录(分配员工ID,分配岗位等)。
    • 为新员工分配部门。
    • 建立员工的工资和奖金记录。

        如果其中一个步骤失败,则系统必须撤销在此之前的所有变化,删除所有不完整的记录的痕迹,以避免以后的不一致和计算错误。

       在 开始事务提交事务 之间所作的所有操作 构成一个事务, 其中任何一个步骤失败都会都会导致整个事务被撤销,系统会返回到以前的状态。

    事务提交后,对数据的修改是永久的,即使系统出现故障也不会丢失数据。

    二.事务的操作

    1.事务的提交

    事务的提交方式有 自动提交手动提交

    在MySQL命令行的默认下,事务都是自动提交的,即执行SQL语句后会马上执行commit操作,我们之前所写的所有单条的DML SQL语句,在MySQL默认是一个事务,默认执行完,就会被MySQL自动提交。

    如果要受到的提交可以使用 begin 或者 start transaction,或者将 AUTOCOMMIT=0,表示禁用自动提交。如下:

    show variables like 'autocommit';//查看是否启动为自动提交。

    SET AUTOCOMMIT=0;//禁用自动提交

    2.开始事务

    手动启动一个事务可以采用如下语句:

    start transaction; 或者 begin;

    begin 和  commit 之间的所有操作 统称为一个事务。

     3.结束事务

    commit语句是提交语句,它使得自从事务开始以来所执行的所有数据修改成为数据库的永久部也标记一个事务的结束

    4.事务的回滚

    事务回滚有语句有

    • rollback :直接回滚到事务的最开始,也就是撤销了该事务的所有操作。
    • rollback to 保存点名称:回滚到设置保存点的位置,撤销了设置保存点之后的所有操作。
    • savepoint 名称:设置保存点,并设置保存点的名称。

    三.事务的属性

    在MySQL中只有使用了 Innodb存储引擎 的数据表才支持事务,MyISAM不支持

    事务的属性包括 原子性,一致性,隔离性,永久性

    原子性

    原子性 意味着每个事务都必须看作一个不可分割的单元,假设一个事务由两个或多个操作组成,其中这些操作必须同时成功,则整个事务才成功否则事务失败,失败将会返回该事务以前的状态。

    在添加员工这个例子中,原子性指如果没有创建员工的工资表和部门,就不可能将员工插入到数据库表中。总而言之,原子执行是一个或者全部发送或者什么也没有发生的命题。

    一致性

    事务

    隔离性

    数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以 防止多个事务并发执行时 由于多个事务的交叉执行 导致数据库中的数据的不一致。比如:事务A正在不断的在修改表中的数据,那么事务B需要不断的查看表的数据,那么事务B每次查看的数据可能不一样。

    持久性

    事务提交后,对数据的修改就是 永久的,即便系统故障也不会丢失。

    一致性

    为了理解一致性,举个通俗易懂的例子:假设我要提现1500块钱提现到银行卡中,那么就需要至少需要分两步操作:

    1. 微信钱包-1500块钱。
    2. 银行卡+1500块钱
    • 当第一步执行后,服务器出现问题导致第二步就无法完成,那么我们的微信钱包-1500快钱,银行卡上的钱没有增加,导致我白白丢失了1500块钱,这就导致数据“不一致"的问题.
    • 事务的一致性与事务原子性有关,如果第二步执行失败,则会回滚到事务的开始,撤销第一步的操作,所以为了保持事务的一致性,在业务层上设计上,就要求我们合理的设计这两步操作,需要将上面的两个操作设计在一个事务内。

    四. 隔离级别

    1.如何理解隔离级别

    • MySQL服务可能被多个客户端同时给访问,访问的方式是以事务的形式访问。
    • 一个事务由多条SQL语句组成,任何一个事务都有执行前(begin之前),执行中(begin和commit之间),执行后(commit之后),如果所有的事务各自执行中有多条事务语句,那么可能会相互影响到的情况,例如:多个事务访问同一张表,同一行数据,有些事务在修改,有些事务在读取。
    • 数据库中为了保证事务的过程中尽量不受干扰,就有了一个重要特征:隔离性。
    • 数据库中,允许事务受不同程度的干扰,就有了一种重要的特征:隔离级别。

    2. 隔离级别的分类

    SQL标准定义了4类隔离级别,包括一些具体规则,用来 限定事务内外的哪些改变是可见的,哪些是不可见的,低级别的隔离级别一般支持更高的并发处理,并拥有更低的系统开销。不同的场景使用的隔离级别可能不同。

    读未提交(READ UNCOMMITTED)

    • 所有的事务可以看到其它事务未提交的结果。读未提交隔离级别很少应用于实际应用中。
    • 一个事务在执行中,读到另一个事务正在更新但没有提交的数据,这种现象就为脏读

    查看客户端的隔离级别:

    select @@tx_isolation; //查看隔离级别

     将当前会话的事务A的隔离级别设置为读未提交READ-UNCOMMITTED;

    set session tx_isolation='READ-UNCOMMITTED';
    

     如果要设置全局的事务隔离级别(其他会话也会改变),那么需要将session 更改为global,如果隔离级别没有生效,则需要重新登录会话才会生效。

    set global tx_isolation='READ-UNCOMMITTED';

     实验1:观察读未提交的现象

    客户端A开始一个事务,并往person表中插入数据,客户端B启动一个事务并查看person表。

    person表:

    客户端A:

     客户端B:

    • 客户端A没有提交事务,但是客户端B的事务可以看到客户端A事务执行过程中插入的数据,这就是读未提交的现象。
    • 客户端B的事务 看到 客户端A的事务 对表的操作,这就是脏读。

    读提交(READ COMMIT)

    • 一个事务 只能看到 已经提交事务的操作正在执行的事务的操作是看不到的,这种隔离级别也支持所谓的不可重复读,因为同一事务的其他实例在该实例处理期间可能会有新的commit,所以同一事务进行查询时可能会返回不同的结果。
    • 该隔离级别是大部分数据库的隔离级别,但不是MySQL的隔离级别。

    实验2:查看读提交的现象

    将隔离级别设置为读提交,客户端A启动一个事务并给person表插入数据,客户端B查看person表,接下来客户端A提交事务,客户端A再查看person表。

     person表:

    客户端A插入数据,但没有提交事务,客户端B查看不到插入的数据

     客户端A提交事务,客户端B可以查看到客户端A插入的数据

    客户端B的事务只能查看到客户端A事务提交的数据,这就是读提交。

    实验3:查看不可重复读的现象

    客户端B开始一个事务并查看person表,然后客户端A开始一个事务并修改person表中的关羽的qq值,然后提交,最后客户端B再查看person表中的数据.

    person表:

    客户端A:

     客户端B:

         

    客户端A事务提交事务前和提交事务后客户端B的事务查看表的数据是不一致的,这就是不可重复读的现象。

    可重复读(REPEATABLE READ)

    • 可重复读是MySQL的默认事务隔离级别。
    • 可重复读隔离级别只允许读取已经提交的记录,而且在 同一个事务两次读取一个记录期间保持一致,但是该事务不要求于其他事务可串行化。
    • 一个事务可以到由一个已经提交更新的记录,但是可能出现幻读的问题。
    • 幻读指当用户读数据行时,另一个事务又在该范围内插入了新行,当用户在读取该范围的数据行,读取到的记录是不一样的。
    • 但是MySQL通过多版本并发控制机制解决了幻读的问题

    实验4:查看可重复读的现象

    将隔离级别设置为可重复读。

    客户端B开始一个事务并查看person表,然后客户端A开始一个事务并修改person表中的关羽的qq值,然后提交,最后客户端B再查看person表中的数据.

    person表:

     客户端A:

     客户端B:

          

     由上面实验可以看到,客户端A的事务修改数据后,不管有没有提交事务,客户端B每次查看数据时只会显示第一次查看到的数据,且在一个事务内只能读取一个记录,期间保持一致,直到客户端B将事务提交,才能读取别的事务修改的记录。
    .

    串行化(SERIALIZABLE)

    •  串行化是最高的隔离级别,它通过强制事务排序,可串行化是一个调度,即多个事务之间的执行方式;而多个事务之间的执行有个先后顺序,如果事务之间没有共同的操作对象(读或写操作),则事务之间的执行顺序前后置换是没有关系的但是如果事物间存在共同的操作对象,则事务间先后执行的顺序则需要区分 。
    • 序列化是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用     

  • 相关阅读:
    24、AT 指令设置AP跟Station模式
    MySQL备份与恢复
    【编程题】【Scratch四级】2022.09 班级成绩处理
    接口自动化测试框架搭建详解
    Rust和Pytho写一段采集公众号代码
    Linux常见基本指令合集及其效果展示
    如何解决香港服务器使用的常见问题
    数据挖掘与分析课程笔记(Chapter 15)
    Qt实现动态桌面小精灵(含源码)
    redux太繁琐?一文入门学会使用mobx简化项目的状态管理
  • 原文地址:https://blog.csdn.net/sjp11/article/details/125994708