InnoDb RR隔离级别需要注意的一个坑

问题

在并发更新同一行记录场景下(比如调用下游系统可能返回同步结果和异步结果(mq消息),目前更新订单表是通过乐观锁(根据订单原状态做判断)做并发控制):

开启事务-》更新订单A-》判断update返回值是否>0?继续下面的流程:否则重新查询订单A的状态看是否已经被其他线程更新-如果已经更新到目标状态则正常返回,否则抛出异常

在批量更新的时候,可能出现异常情况:

开启事务-》更新订单A-》判断update返回值是否>0?更新订单B(-》更新订单C..):否则重新查询订单A|B|C的状态看是否已经被其他线程更新-如果已经更新到目标状态则正常返回,否则抛出异常

可能更新订单B|C的情形下查出的结果有时是原状态但是数据库实际上已经更新到目标状态

实验

在console1:

BEGIN;
select status from Order where id = 'A';
SELECT SLEEP(10);
SELECT  status from Order where id = 'B';
COMMIT

console1的sleep期间在console2执行:

BEGIN;
UPDATE Order SET `status` = '失败' where id = 'B'and `status` = '处理中';
COMMIT;

可看到结果是处理中而非console2执行之后的失败。

原因

InnoDb 默认隔离级别是RR,在此级别下,开启事务之后做select属于Consistent Nonlocking Reads,(而update、select for update这类语句属于 locking read),

RR级别的情况下,开启事务,如果订单A(有并发更新,并)做了select查询那么订单B做select查询的时候的结果仍然是订单A做select查询那一刻的结果

rc每次快照读时都会去更新事务id数组,rr只在一开始时创建数组

Reference

Mysql可重复读

Transaction Isolation Levels

Consistent Nonlocking Reads

locking read

转载于:https://www.cnblogs.com/liwanping/p/11147155.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值