数据库-不可重复读的演示

不可重复读的演示

目标

能够解决不可重复读

讲解

不可重复读:一个事务中两次读取的数据内容不一致,要求的是一个事务中多次读取时数据是一致的,这是事务update时引发的问题。

将数据进行恢复:

UPDATE account SET balance = 1000;
  1. 开启A窗口

    set global transaction isolation level read committed;
    

    [外链图片转存失败(img-rQfb4Rpy-1562514234359)(img/事务42.png)]

  2. 开启B窗口,在B窗口开启事务,并查询数据

    start transaction;
    select * from account;
    

    [外链图片转存失败(img-0lVtPE93-1562514234360)(img/事务43.png)]

  3. 在A窗口开启事务,并更新数据

    start transaction;
    update account set balance=balance+500 where id=1;
    commit;
    

    在这里插入图片描述

  4. B窗口查询

    select * from account;
    

    [外链图片转存失败(img-0h7RaQiI-1562514234360)(img/事务45.png)]

两次查询输出的结果不同,到底哪次是对的?不知道以哪次为准。
很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客户,结果在一个事务中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。

解决不可重复读的问题:将全局的隔离级别进行提升为:repeatable read
将数据进行恢复:

UPDATE account SET balance = 1000;
  1. A窗口设置隔离级别为:repeatable read

    set global transaction isolation level repeatable read;
    

    [外链图片转存失败(img-zIvdIls6-1562514234361)(img/事务46.png)]

  2. B窗口退出MySQL,B窗口再进入MySQL,并查询数据

    start transaction;
    select * from account;
    

    [外链图片转存失败(img-mArjGl6f-1562514234361)(img/事务47.png)]

  3. A窗口更新数据

    start transaction;
    update account set balance=balance+500 where id=1;
    commit;
    

    [外链图片转存失败(img-jAA5Puvf-1562514234362)(img/事务48.png)]

  4. B窗口查询

    select * from account;
    

    [外链图片转存失败(img-1515nDJq-1562514234364)(img/事务49.png)]

结论:同一个事务中为了保证多次查询数据一致,必须使用repeatable read隔离级别
[外链图片转存失败(img-7rBivLe0-1562514234367)(img/事务50.png)]

幻读的演示

目标

能够解决幻读

讲解

幻读:**是指在一个事务内读取到了别的事务插入的数据,导致前后读取记录行数不同。**这是insert或delete时引发的问题

幻读演示

  1. 开启A窗口,开启事务,并查询id>1的数据

[外链图片转存失败(img-OEh1IWdB-1562514234367)(img/1551413050280.png)]

  1. 开启B窗口,开启事务,添加一条数据,并提交事务

    [外链图片转存失败(img-mFqPc7Eo-1562514234367)(img/1551413102060.png)]

  2. 在A窗口修改id>数据的balance为0,并重新查询id>1的数据

[外链图片转存失败(img-LC6CY9kd-1562514234368)(img/1551413309793.png)]

我们可以将事务隔离级别设置到最高,以挡住幻读的发生
将数据进行恢复:

UPDATE account SET balance = 1000;
  1. 开启A窗口

    set global transaction isolation level serializable; -- 设置隔离级别为最高
    

    [外链图片转存失败(img-9iBHOvKr-1562514234368)(img/事务51.png)]

  2. A窗口退出MySQL,A窗口重新登录MySQL

    start transaction;
    select count(*) from account;
    

    [外链图片转存失败(img-pEngt3Wo-1562514234368)(img/事务52.png)]

  3. 再开启B窗口,登录MySQL

  4. 在B窗口中开启事务,添加一条记录

    start transaction; -- 开启事务
    insert into account (name,balance) values ('LaoWang', 500);
    

    [外链图片转存失败(img-YQBxtOUZ-1562514234369)(img/事务53.png)]

  5. 在A窗口中commit提交事务,B窗口中insert语句会在A窗口事务提交后立马运行
    [外链图片转存失败(img-HMGHb3F8-1562514234369)(img/事务54.png)]

  6. 在A窗口中接着查询,发现数据不变

    select count(*) from account;
    

    [外链图片转存失败(img-qpUVEEes-1562514234369)(img/事务55.png)]

  7. B窗口中commit提交当前事务
    [外链图片转存失败(img-IHeaJgdv-1562514234369)(img/事务56.png)]

  8. A窗口就能看到最新的数据
    [外链图片转存失败(img-fPRFWNv5-1562514234370)(img/事务57.png)]

结论:使用serializable隔离级别,一个事务没有执行完,其他事务的SQL执行不了,可以挡住幻读。

通过提高隔离级别到串行化,可以避免并发访问的所有的问题,但效率太低。

gdv-1562514234369)]

  1. A窗口就能看到最新的数据
    [外链图片转存中…(img-fPRFWNv5-1562514234370)]

结论:使用serializable隔离级别,一个事务没有执行完,其他事务的SQL执行不了,可以挡住幻读。

通过提高隔离级别到串行化,可以避免并发访问的所有的问题,但效率太低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值