补充上个帖子的分布式事务之扣减库存(秒杀?)

本文探讨了使用数据库事务处理在不同场景下的一致性保证策略,包括如何通过优化事务传播类型减少锁竞争,并介绍了实现远程过程调用(RPC)下单过程中的一致性方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       当业务规模不大,并且对于生成订单并冻结库存等操作要求一致性较高时,使用数据库的事务特性来保证一致性;

       比如有如下场景:

步骤相关业务
1冻结库存(保证下单时有足够的库存)
2生成对应的订单
3支付订单,扣减冻结库存

(1)该场景如果仅使用ACID数据库进行控制,则伪代码为:

@Transactional(rollbackFor = Exception.class)
public Result placeOrder(xxx xxx){
     //直接进行冻结扣减库存
     boolean b = deductionInventory(xxx);
     if(!b){
       //抛出异常中断
     }
     //进行订单生成等其他业务操作;
}

以上代码能够应付一般的并发下单了,但是如果涉及到下单有多个商品,在扣除库存前有其他事务(例如需要扣除积分,但是积分操作只涉及用户个人),那么整个方法将是一个大事务,相关的库存行锁将占用时间较长,影响了其他用户的下单;

(2)根据以上问题,优化一下,将扣除库存及生成订单的操作提取出来,并且使用REQUIRES_NEW事务传播类型,旨在完成冻结库存成功后,结束当前事务操作,进行后续耗时操作;

@Transactional(rollbackFor = Exception.class)
public Result placeOrder(xxx xxx){
     //相关的用户积分业务事务操作,此时只锁住该用户积分行
     userservice.do(xxx);
        
     //新建独立事务扣除库存及生成订单,成功后直接释放商品库存行锁;当出现不足等可跟积分事务一起回滚
     //@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
     boolean b = newService.deductionInventoryAndPlaceOrder(xxx);
     if(!b){
       //抛出异常中断,并回滚积分业务
     }
   
}

(3)其实在冻结库存时可能还会出现个问题,就是可能会出现MySQL的循环占用资源死锁的问题,具体相关概念可以去其他地方查询,我这里给出的最简单的方法就是将用于扣减库存的商品列表,使用某一字段进行排序避免;此方式同样适用于调度任务在处理批量回滚商品库存等业务中;

(4)比如我们想在该下单方式的基础上,支持RPC调用,例如商品是单独服务,订单又是单独服务,如何保证一致性:

@Transactional(rollbackFor = Exception.class)
public Result placeOrder(xxx xxx){
     //直接进行冻结扣减库存,并且存储冻结库存订单
     boolean b = deductionAndSaveInventory(xxx);
     //deductionAndSaveInventory方法包括以下操作,均为本地事务操作:
     //扣减库存,保存冻结库存的日志

     if(!b){
       //抛出异常中断
     }

     //进行订单生成等其他业务操作;
     boolean b = RPC.createOrder(xxx);
     //生成订单业务包括:生成订单,删除冻结库存日志;
}


task:根据生成时间等条件查询冻结库存日志,进行回滚;

 以上方式,可能会存在下单失败,但是暂时将库存扣除的问题,这就要合理的规划调度回滚库存以及根据具体业务场景选择下单方式;

(5)其他的下单方式,例如:

1)在付款时在进行扣减库存,判断是否可以支付;

2)不在意库存扣为负数,或者有其他方式避免库存不足,不需要判断库存,则直接可以下单成功使用消息队列等方式,进行最终一致性的重试;

使用单条语句达到查询库存扣减库存的一致性:

1)使用类似乐观锁方式:(更新检查)

UPDATE item SET inventory = CASE WHEN inventory >= xxx THEN inventory-xxx ELSE inventory END

 2)将库存字段设为无符号类型,如果扣减更新为负数则报错回滚;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值