数据库并发操作可能出现的问题及解决方式

并发操作可能出现的问题
问题描述
第1类丢失更新事务A撤销时,把已经提交的事务B的更新数据覆盖了
第2类丢失更新事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。
脏读A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。
幻读事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行
不可重复读事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了
  • 第1类丢失更新:事务A撤销时,把已经提交的事务B的更新数据覆盖了
时间取款事务A转账事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5汇入100元修改余额为1100元
T6提交事务
T7取出100元将余额修改为900元
T8撤销事务
T9余额恢复为1000元(丢失更新)
  • 第2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。
时间转账事务A取款事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5取出100元将余额修改为900元
T6提交事务
T7汇入100元将余额修改为1100元
T8提交事务
T9查询账户余额为1100元(丢失更新)
  • 脏读(Dirty Read):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。
时间转账事务A取款事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4取出500元余额修改为500元
T5查询账户余额为500元(脏读)
T6撤销事务余额恢复为1000元
T7汇入100元把余额修改为600元
T8提交事务
  • 幻读(Phantom Read):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。
时间统计金额事务A转账事务B
T1开始事务
T2开始事务
T3统计总存款为10000元
T4新增一个存款账户存入100元
T5提交事务
T6再次统计总存款为10100元(幻读)
  • 不可重复读(Unrepeatable Read):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。
时间转账事务A取款事务B
T1开始事务
T2开始事务
T3查询账户余额为1000元
T4查询账户余额为1000元
T5取出100元修改余额为900元
T6提交事务
T7查询账户余额为900元(不可重复读)
如何处理

使用锁机制:
mysql中设置事务隔离级别,自动加锁

读未提交 – 会发生脏读。
读提交 – 会发生不可重复读,不会读到脏数据。
可重复读 – 重复读到之前的数据,在一个事务中。

隔离级别第一类丢失更新第二类丢失更新脏读幻读不可重复读
READ UNCOMMITED不允许允许允许允许允许
READ COMMITTED不允许允许不允许允许允许
REPEATABLE READ不允许不允许不允许允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许

需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。

测试不同隔离级别下并发操作出现的问题

在Linux系统中进行测试
因为mysql是自动提交的,首先开启事务环境
使用 begin 或者 start transaction 都可以开启一个事务环境

开启事务环境

mysql> begin; 
mysql> start transaction ;

提交事务

mysql> commit;

回滚事务

mysql> rollback;

查看事务

mysql> select @@tx_isolation;

在这里插入图片描述
设置事务隔离级别

mysql> set session transaction isolation level read uncommitted;

同时开启两个窗口,对同一个数据进行操作,对并发操作出现的问题进行测试

  • 场景一:读脏数据
        事务A:
            ~ begin;
            ~ update tb_emp set sal=2800 where eno=1359;
        事务B:
            ~ set session transaction isolation level read uncommitted;
            ~ begin;
            ~ select * from tb_emp; ---> 读脏数据
            ~ commit;
        事务A:
            ~ rollback;
  • 场景二:不可重复读
    事务B:
        ~ set session transaction isolation level read committed;
        ~ begin;
        ~ select * from tb_emp where sal<3000;
    事务A:
        ~ begin;
        ~ update tb_emp set sal=3800 where eno=1359;
        ~ commit;
    事务B:
        ~ select * from tb_emp wehre sal<3000; ---> 没有1359对应的记录了,不可重复读
        ~ commit;
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值