• 高并发操作同一条数据,更新丢失数据问题(重复转账,票超卖,订单扣库存问题)


    何为更新丢失数据问题:假设数据库中有一条数据,有两个事物A,B,同时对这条数据操作。事物A,B同时读到这条数据,事物A对这条数据进行修改并提交,然后事物B对这条数据修该改但晚于事物A提交。这种情况下事物B就会覆盖掉事物A的更新,事物A的更新就会丢失。这种情况有时会引起比较严重的问题。例如重复转账问题,例如一个账户A有100元余额,要向账户B进行转账100元的操作,通常会分为两步,首先读出账户A的余额,判断是否余额充足,然后进行转账扣款操作。如果同时有两个事物a,b进行这个操作,他们同时读到账户余额余额是100,于是他们都判断余额充足,事物A首先进行转账扣款操作,并提交。这个时候账户B已经得到100元转账,账户A余额是0.然后事物b,也进行转账扣款操作,并提交。这个时候,账户B再次得到100元转账,账户A的余额被修改成0.也就是说账户A最终扣款100,账户B却得到200元。票超卖问题也是类似的。

    解决方案:1.在事物读取账户余额的语句中加排他锁,这样两个事物就无法同时读取到相同的余额。这种处理方法就是强制事物串行处理。缺点是并发量不高,处理的慢。

                      2.用乐观锁,给数据加乐观锁。也就是加一个版本号version字段。事物读取数据的同时,读取到版本号,提交的时候把版本号加一,并加上版本号判断。语句如下

                       update  table set Num=0,Version=Version-1 where Version=读到的版本号。这样如果事物A提交成功,版本号加一,事物B后提交时就会修改失败。可以根据修改影响的行数来判断。这样就可以避免更新丢失。可以根据业务进行重试。缺点并发量不能太高。

        以上两种解决方案都是数据库层面的。

    下面在以电商抢购,下单与扣库存的业务场景提出如下两种解决方案:

                      3.将数据放到redis 缓存中。用分布式锁,强制同一时间只能有一个事务对数据操作,本质上也是将事务串行化操作。缺点并发量不高。

                      4.利用Redis increment 的原子操作(就是更新与读取是原子性的)和redis的单线程特点(这两个特点就可以保证不同的事务不会读到相同余额的问题),保证库存安全。 事先需要把库存的数量等其他信息保存到Redis,并保证更新库存的时候,更新Redis。 进来的时候 先 get 库存数量是否充足,再执行 increment。以 increment > 0 为准。 检查库存 与 减少库存 不是原子性的。 检查库存的时候技术库存充足也不可下单;否则造成库存不安全,原来类似 方法1. increment 是个原子操作,已这个为准。

    redisService.increment(key, -req.getNum().longValue()) >= 0 说明库存充足,可以下单。

    redisService.increment(key, -req.getNum().longValue()) < 0 的时候 不能下单,次数库存不足。并且需要 回加刚刚减去的库存数量,否则会导致刚才减扣的数量 一直买不出去。数据库与缓存的库存不一致。

    参考文章:https://blog.csdn.net/mifffy_java/article/details/95201752

    次方法可以满足 高并抢购等一些方案,真正减扣库存和下单可以异步执行。

    订单时效问题,订单取消等 为保证商家利益,同时把商品卖给有需要的人,订单下单成功后,往往会有个有效时间。超过这个时间,订单取消,库存回滚。

    订单取消后,可利用MQ 回退库存等。缺点是如果redis 服务停止,将无法下单。

                     

  • 相关阅读:
    mysql内置函数,在mysql里面利用str_to_date()把字符串转换为日期格式
    异步httpclient(httpasyncclient)的使用与总结
    spring中Constructor、@Autowired、@PostConstruct的顺序
    面试再问值传递与引用传递,把这篇文章砸给他!
    java float double bigdecimal
    XSD详解一
    Springboot中使用Xstream进行XML与Bean 相互转换
    lombok标签之@Data @AllArgsConstructor @@NoArgsConstructor -如何去除get,set方法。@Data注解和如何使用,lombok
    Spring标签之Bean @Scope
    spring 注解 之 AOP基于@Aspect的AOP配置
  • 原文地址:https://www.cnblogs.com/gfbppy/p/13757249.html
Copyright © 2020-2023  润新知