zoukankan      html  css  js  c++  java
  • MySQL(23):事务的隔离级别出现问题之 脏读

    1. 脏读

      所谓的脏读就是指一个事务读取了另一个事务未提取的数据。

    试想一下:a账户要给b账户100元购买商品,如果a账户开启一个事务,执行下面的update语句做了如下转账的工作:

    update account set money=money-100 where name='a';
    update account set money=money+100 where name='b';

    如果a账户先不提交事务,通知b账户来查询,由于b的隔离级别比较低,此时就会读取a事务中未提交的数据,发现a确实给自己转了100元,然后给a发货,等b发货成功之后,a再将事务回滚,此时b就会受到损伤,这就是脏读造成的。

     

    为了演示上面的情况,这里我们开启了两个命令行窗口(相当于开启两个线程),分别模拟a账户和b账户,如下:

     

    (1)设置b账户中事务的隔离级别

    大家都知道MySQL的默认隔离级别是Repeatable Read(可重复读),该级别是可以避免脏读的,因此需要将b账户中事务的隔离级别设置为Read Uncommitted(读未提交),具体语句如下:

    set session transaction isolation level read uncommitted;

    如下:

     

    上述语句之中,session表示当前会话,transaction就表示事务,isolation表示隔离,level表示级别,read uncommitted表示当前的隔离级别,该语句执行成功之后,使用select语句查询事务的隔离级别,结果如下:

    select @@tx_isolation;

    如下:

     

    从上述结果可以看出,b账户的事务隔离级别以及修改为Read Uncommitted,接下来就是演示脏读的情况

     

    (2)演示脏读

    b账户:为了证明出现了脏读的情况,首先在b账户中开户一个事务,并在该事务中查询当前账户的余额信息,查询结果如下:

    start transaction;
    select * from account;

    如下:

     

     

    a账户:在a账户中开启一个事务,并在当前窗口中执行转账功能,具体语句如下:

    start transaction;
    update account set money=money-100 where name='a';
    update account set money=money+100 where name='b';

    如下:

    需要注意的是:此时不要提交事务,如果提交事务就无法演示出现脏读的情况。

     

    b账户:a账户执行完转账语句后,b账户查询当前账户,如下:

    从上面的查询结果来看,a账户已经成功给b账户转账了100元,这是由于b账户的事务隔离级别比较低,因此才读取了a账户还没有提交的数据内容,出现了脏读的情况,这时候,b误以为a账户以及转账成功,便会给a发货,当b发货之后a如果不提交事务将事务回滚,b就会受到损失。

    上面演示完毕了,需要将a账户中的事务回滚,b账户中的事务提交。

    (3)设置b账户的事务隔离级别

    为了防止脏读发生,可以将b账户中的事务隔离级别设置为Read Committed(读提交),该级别会避免脏读,具体语句如下:

    set session transaction isolation level read committed;

    上述的语句执行成功之后,b账户的隔离级别已经设置成Read Committed

    (4)验证是否出现脏读

    b账户:为了说明没有出现脏读的情况,首先要在b账户中开启一个事务,并在该事务中查询各账户的余额情况,查询结果如下:

    a账户:在a账户中重新开启一个事务,实现了转账功能,如下:

    start transaction;
    update account set money=money-100 where name='a';
    update account set money=money+100 where name='b';

    b账户:当a 账户转账成功之后,可以在b账户中再次查询各账户的余额信息,查询结果如下:

     通过上面的对比两次查询结果可以发现,b账户在同一个事务中的查询结果是一致的,并没有查询到a账户中未提交的内容,因此可以说明Read Committed 隔离级别可以避免脏读,最后分别将a账户和b账户中的事务回滚(方便以后演示)。

  • 相关阅读:
    windows10远程桌面慢的解决
    linux挂载windows共享盘
    ORACLE 临时表空间满了的原因解决方案
    oracle临时表空间扩容
    expdp/impdp 数据泵导入导出
    Oracle Awr报告_生成
    mysql备份与保存
    oracle lsnrctl监听器多实例配置
    RabbitMQ
    docker stop 容器时 不能将我指定的容器停掉
  • 原文地址:https://www.cnblogs.com/hebao0514/p/5490764.html
Copyright © 2011-2022 走看看