• 12【事务的隔离级别】



    上一篇11【事务处理】


    下一篇13【触发器】

    目录【MySQL零基础系列教程】



    12【事务的隔离级别

    12.1 并发访问的三个问题

    并发访问下事务产生的问题:

    当同时有多个用户在访问同一张表中的记录,每个用户在访问的时候都是一个单独的事务。

    事务在操作时的理想状态是:事务之间不应该相互影响,实际应用的时候会引发下面三种问题。应该尽量避免这些问题的发生。通过数据库本身的功能去避免,设置不同的隔离级别

    • 脏读: 一个事务(用户)读取到了另一个事务没有提交的数据
    • 不可重复读:一个事务多次读取同一条记录,出现读取数据不一致的情况。一般因为另一个事务更新了这条记录而引发的。
    • 幻读:在一次事务中,多次读取到的条数不一致

    12.2 设置隔离级别

    12.2.1 四种隔离级别:

    级别名字隔离级别脏读不可重复读幻读数据库默认隔离级别
    1读未提交read uncommitted
    2读已提交read committedOracle和SQL Server
    3可重复读repeatable read是/否MySQL
    4串行化serializable

    12.2.2 四种隔离级别起的作用:

    • 1)Read uncommitted (读未提交): 简称RU隔离级别,所有事务中的并发访问问题都会发生,可以读取到其他事务没有提交的数据

    • 2)Read committed (读已提交):简称RC隔离级别,会引发不可重复读和幻读的问题,读取的永远是其他事务提交的数据

    • 3)Repeatable read (可重复读):简称RR隔离级别,会引发幻读的问题,一次事务读取到的同一行数据,永远是一样

    • 4)Serializable (串行化): 可以避免所有事务产生的并发访问的问题 效率及其低下

    12.3 安全和性能对比

    • 隔离级别越高,安全性就越高,性能越低
    • 隔离级别越第,安全性就越低,性能越高。

    12.4 MySQL相关的命令:

    查询全局事务隔离级别

    mysql> select @@tx_isolation;
    +-----------------+
    | @@tx_isolation  |
    +-----------------+
    | REPEATABLE-READ |
    +-----------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    设置全局事务隔离级别

    set global transaction isolation level 四种隔离;		-- 服务器只要不关闭一直有效
    
    • 1

    修改隔离级别后需要重启会话

    12.5 脏读

    在并发情况下,一个事务读取到另一个事务没有提交的数据,这个数据称之为脏数据,此次读取也称为脏读。

    只有read uncommitted(读未提交)的隔离级别才会引发脏读。

    • 将MySQL的事务隔离级别设置为read committed(读已提交):
    mysql> set global transaction isolation level read uncommitted;
    Query OK, 0 rows affected (0.00 sec)
    
    • 1
    • 2

    将数据还原:

    在这里插入图片描述

    12.5.1 脏读演示

    session-01session-02
    begin;
    begin;
    select * from account where name=‘a’;
    update account set money=money-200 where name=‘a’;
    select * from account where name=‘a’;
    rollback;

    观察变化:

    在这里插入图片描述

    12.5.2 解决脏读

    将全局的隔离级别进行提升

    1. 打开命令行a,设置全局的隔离级别为read committed:
    set global transaction isolation level read committed;
    
    • 1

    再次执行:

    session-01session-02
    begin;
    begin;
    select * from account where name=‘a’;
    update account set money=money-200 where name=‘a’;
    select * from account where name=‘a’;
    rollback;

    观察变化:

    在这里插入图片描述

    12.6 不可重复读

    概念: 在同一个事务中的多次查询应该出现相同的结果,两次读取不能出现不同的结果。

    12.6.1 和脏读的区别:

    脏读是读取前一事务未提交的脏数据,不可重复读是重复读取了前一事务已提交的数据,但2次读取的结果不同。

    应用场景:比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,两次输出结果却不一致,导致文件和屏幕中的结果不同,银行工作人员就不知道以哪个为准了。

    12.6.2 不可重复读演示

    1). 将数据进行恢复,并关闭窗口重新登录。

    update account set money=1000;
    
    • 1
    session-01session-02
    begin;
    begin;
    select * from account where name=‘a’;
    update account set money=money-200 where name=‘a’;
    commit;
    select * from account where name=‘a’;

    观察变化:

    在这里插入图片描述

    两次查询输出的结果不同,到底哪次是对的?

    12.6.3 解决不可重复读

    1)将数据进行恢复

    update account set money=1000;
    
    -- 设置隔离级别为repeatable read
    set global transaction isolation level repeatable read;
    
    • 1
    • 2
    • 3
    • 4

    记得要重启窗口

    session-01session-02
    begin;
    begin;
    select * from account where name=‘a’;
    update account set money=money-200 where name=‘a’;
    commit;
    select * from account where name=‘a’;

    观察变化:

    在这里插入图片描述

    结论:为了保存多次查询数据一致,必须使用repeatable read隔离级别

    12.7 幻读

    概念:一次事务多次读取到的条数不一致而引发的问题;

    在InnoDB(暂时理解是MySQL)中幻读在很多地方都得到了解决,但在一些特殊的情况下,还是会引发幻读问题;

    为什么有的情况下能解决,有的情况下解决不了?因为一次事务多次读取到的条数不一致会导致有很多情况发生!

    12.7.1 幻读解决情况1):

    还原数据:

    update account set money=1000;
    
    -- 设置隔离级别为repeatable read
    set global transaction isolation level repeatable read;
    
    • 1
    • 2
    • 3
    • 4

    记得重启客户端

    session-01session-02
    begin;
    begin;
    select * from account;
    insert into account values(3,‘c’,1000);
    commit;
    select * from account;

    观察变化:

    在这里插入图片描述

    幻读问题得到解决

    12.7.2 幻读解决情况2):

    还原数据

    案例:

    session-01session-02
    begin;
    begin;
    select sum(money) from account;
    insert into account values(3,‘c’,1000);
    commit;
    select sum(money) from account;

    观察变化:

    在这里插入图片描述

    12.7.3 幻读问题出现情况1):

    还原数据

    • 案例:
    session-01session-02
    begin;
    begin;
    select count(id) from account;
    insert into account values(3,‘c’,1000);
    commit;
    select count(id) from account;
    update account set money=0;
    select count(id) from account;

    观察变化:

    在这里插入图片描述

    12.7.3 特殊情况:

    还原数据

    • 案例:
    session-01session-02
    begin;
    begin;
    select * from account;
    select * from account;
    insert into account values(3,“c”,1000);
    commit;
    select * from account;
    insert into account values(3,“c”,1000);

    观察变化:

    在这里插入图片描述

    Tips:严格意义来说,上述案例是MySQL的快照机制导致的,不能算幻读;关于幻读我们理解概念就行,即:两次读取到的条数不一致!这就是幻读

    12.9 串行化

    12.9.1 概念

    想要彻底的解决幻读,那么我们必须再把隔离级别调高,数据库的最高隔离级别为串行化(serializable)

    串行化相当于锁表操作,即一个事务如果操作了某张表(增加、删除、修改),那么就不允许其他任何事务操作此表,也不允许查询,等第一个事务提交或者回滚之后才可以操作,这样做效率及其低下,因此一般不会采用serializable隔离级别

    • 示例图:
      在这里插入图片描述

    12.9.2 串行化演示

    1)开启一个银行窗口

    -- 还原数据
    truncate account;
    
    INSERT INTO account (name, money) VALUES ('a', 1000), ('b', 1000);
    
    set global transaction isolation level serializable; 	-- 设置隔离级别为串行化
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)执行案例:

    session-01session-02
    begin;
    begin;
    update account set money=money-500 where name=‘a’;
    select * from account;

    在这里插入图片描述

    在串行化隔离级别中,相当于锁表的操作,在一个事务对表进行任何的insert/update/delete等操作时,其他事务均不可对其进行操作;在读写上是串行的,并发能力极差;

  • 相关阅读:
    CSS技能点--垂直导航栏实例
    【Vue3.0移动端项目--旅游网】-- 详情页的标签定位滚动
    图片如何缩小不降低清晰度?
    Java虚拟机(JVM)-- Dump内存快照
    2023华为HCIA+HCIP最全Datacom题库解析
    用node开发微信群聊机器人第②章
    linux网络加固操作
    基于Python的微博舆论分析,微博情感分析可视化系统(V2.0)
    Git Commit Message 规范实践
    js的同步异步
  • 原文地址:https://blog.csdn.net/Bb15070047748/article/details/126568215