Sku扣减库存没有成功

Sku扣减库存没有成功

七月老师好,最近我测试下单接口发现,测试小程序使用林白的测试数据下单一切正常,修改测试小程序下单(1)的下单商品之后,Sku扣减库存存在问题。查看order表有发现下单的记录,但是查看sku表发现对应id商品的库存却没有变化,查看日志显示扣减库存Update语句已经执行,扣减之后额外执行了一句Sku的Update语句,请问老师是这句Update语句导致Sku扣减库存失败的吗?为什么会出现这一句语句?

相关截图:

http://img1.sycdn.imooc.com//climg/5ff0b22709f148d603940747.jpg

http://img1.sycdn.imooc.com//climg/5ff0b280097f9a4210550810.jpg

相关代码:

​@Transactional
public Long placeOrder(Long uid, OrderDTO orderDTO, OrderChecker orderChecker) {
Calendar calendar = Calendar.getInstance();
Date placedTime = calendar.getTime();
calendar.add(Calendar.SECOND, payLimitTime);
Date expiredTime = calendar.getTime();

Order order = Order.builder()
.orderNo(OrderUtil.makeOrderId())
.userId(uid)
.totalPrice(orderChecker.getTotalPrice())
.totalCount(orderChecker.getTotalCount())
.snapImg(orderChecker.getLeaderImg())
.snapTitle(orderChecker.getLeaderTitle())
.finalTotalPrice(orderChecker.getFinalTotalPrice())
.status(OrderStatus.UNPAID.getCode())
.placedTime(placedTime)
.expiredTime(expiredTime)
.build();
order.setSnapItems(orderChecker.getOrderSkuList());
order.setSnapAddress(orderDTO.getAddress());
orderRepository.save(order);

log.info("准备扣减库存");
//扣减库存
this.reduceStock(orderChecker);
log.info("扣减库存成功");
//核销优惠券
if (orderDTO.getCouponId() != null) {
log.info("准备核销优惠券");
this.writeOffCoupon(orderDTO.getCouponId(), uid, order.getId());
log.info("核销优惠券成功");
}
log.info("下单成功,返回订单id");
return order.getId();
}

private void reduceStock(OrderChecker orderChecker) {
orderChecker.getOrderSkuList().forEach(orderSku -> {
int result = skuRepository.reduceStock(orderSku.getId(), orderSku.getCount().longValue());
if (result != 1) {
throw new ParameterException("商品库存不足");
}
});
}

private void writeOffCoupon(Long couponId, Long uid, Long oid) {
int result = userCouponRepository.writeOff(uid, couponId, oid);
if (result != 1) {
throw new ParameterException("优惠券核销失败");
}
}


正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

7回答
7七月 2021-01-03 19:45:12

这几天比较忙,可能没时间看这个,主要是这个场景太不好测试了,是在回调里测试。

你可以按以下思路缩小范围:

  1. 不再回调里 update是否会执行多出的update

  2. 是否是任意的一次update都会导致多出update

先分析清楚这个。一直分析到哪个场景下的update会导致多出这次update

  • 提问者 慕粉3199213 #1

    我在原版程序里面已经注释了回调,placeOrder接口只剩下创建订单、扣减库存、核销优惠券三步操作了,分析结果如下:

    1. 不在回调里,Update依然会执行多出的Update

    2. 不是任意Update都会多出一次Update,placeOrder接口的操作里面核销优惠券的Update操作

    有问题的场景是,如果Sku的specs字段使用List<Spec>的Converter的话,在下单有规格值的Sku的时候,扣减库存这步操作会因为多出的Update导致placeOrder接口返回成功,但数据库里的sku实际的库存却没有扣减的情况

    麻烦老师有空的时候可以帮忙看看哈,谢谢

    2021-01-03 20:20:58
7七月 2021-01-03 19:26:05

我没有碰到过这种问题。但我记得之前在准备这个课程写代码的时候,遇到过一个类似的问题,好像也是会多出一次save。当时排查了下,貌似也是因为 自动序列化造成的。

  • 提问者 慕粉3199213 #1

    我这边是在执行扣减库存的Update语句之后,会多出一次全量的Sku Update语句,因为@Convet这种方式老师您也在课程上提及过,可以使用的,现在我在老师的代码上复现了我遇到的问题,不知道老师方不方便可以帮忙排查一下是什么原因吗?

    2021-01-03 19:31:16
  • 提问者 慕粉3199213 #2

    多出来的这一次全量Sku Update语句,会把扣减库存的Update语句给恢复成没有扣减的记录,所以会出现下单成功,但是库存没扣减的情况

    2021-01-03 19:32:25
  • 提问者 慕粉3199213 #3

    多出来的一次Update会覆盖扣减库存的Update语句,造成下单成功之后,库存没有被扣减的情况,看起来就好像是Sku库存扣减被单独回滚了,但是订单保存却没有回滚

    2021-01-03 19:34:43
7七月 2021-01-03 19:02:54

课程用的不是这个方法呀,用的是getter和setter的方式。这种方式也有问题?

  • 提问者 慕粉3199213 #1

    getter和setter的方式没有问题,我就是想请问下老师,我截图的这种方式为什么会出现这种问题,我在百度上面搜索了一番,也没发现合适的答案,所以特意来请教下老师

    2021-01-03 19:18:19
7七月 2021-01-03 11:00:45

就是课程里讲的。因为要解决问题,就需要复现这个问题。从来没有遇到这样的问题,肯定无法找到原因。

  • 提问者 慕粉3199213 #1

    好,我这边先试试原来的程序会不会出现这个问题吧

    2021-01-03 11:04:00
  • 提问者 慕粉3199213 #2

    测试了一下Git上面的程序,不会多出一个Update,我这边对比了我写的代码和老师您写的代码,暂时没发现不同,还是不清楚问题出在哪里了

    2021-01-03 14:19:27
  • 提问者 慕粉3199213 #3

    7月老师,我在原来的程序里面复现了这个问题,如果把Sku实体的Specs字段声名为List<Spec>,再标记上@Convert的注解,如果下单有规格的Sku商品就会出现问题

    @Converter
    public class SpecListConverter implements AttributeConverter<List<Spec>, String> {
    @Autowired
       private ObjectMapper mapper;

       @Override
       public String convertToDatabaseColumn(List<Spec> specs) {
    try {
    return mapper.writeValueAsString(specs);
           } catch (JsonProcessingException e) {
    e.printStackTrace();
               throw new ServerErrorException("序列化List<Spec>失败");
           }
    }

    @Override
       public List<Spec> convertToEntityAttribute(String s) {
    if (s == null) {
    return Collections.emptyList();
           }
    try {
    return mapper.readValue(s, new TypeReference<List<Spec>>() {
    });
           } catch (JsonProcessingException e) {
    e.printStackTrace();
               throw new ServerErrorException("反序列化List<Spec>失败");
           }
    }
    }
    @Convert(converter = SpecListConverter.class)
    private List<Object> specs;


    2021-01-03 17:50:49
7七月 2021-01-03 10:58:32

原来的程序有 多出这个update吗?

  • 提问者 慕粉3199213 #1

    您是指您放在Git上面的程序吗?

    2021-01-03 10:59:48
7七月 2021-01-03 10:56:31

先不说update。我是想知道,这个在线上的测试都是没有问题的。

你自己用测试的代码OK,然后修改小程序后就出现问题,这个是为什么?

7七月 2021-01-03 03:12:31

只看这个描述很难找到原因。但是你可以对比下一开始的测试程序,看看有什么不同吗?

  • 提问者 慕粉3199213 #1

    我在网上查找了下资料,在SkuRepository的reduceStock函数的@Modifying上追加clearAutomatically=true,就没有执行额外的Update语句了,但不知道为什么会这样,7月老师可以指导一下吗?

    @Modifying(clearAutomatically = true)
    @Query("update Sku s\n" +
    "set s.stock=stock-?2\n" +
    "where s.id=?1\n" +
    "and s.stock>=?2")
    int reduceStock(Long sid, Long count);


    2021-01-03 10:33:29
  • 提问者 慕粉3199213 #2

    相比一开始的测试程序,我只是修改了total_price字段,final_total_price字段,sku_info_list里面的id和count字段,修改的值也是符合程序订单检验的规则的

    2021-01-03 10:56:44
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师