美文网首页
一次Java对象引用使用不当的引起问题

一次Java对象引用使用不当的引起问题

作者: 缄默的石头 | 来源:发表于2017-12-06 19:26 被阅读58次
    1. 背景描述
      铺货的时候要对照bach那边的库存做校验,不同蜂房要查看的sku列表是相同的,但是每个sku在每个蜂房的库存都是不一样的,要把每个蜂房的sku库存情况以Map的形式存储下来,以蜂房的code为key,sku的库存为value,而sku的库存也做成了map,以skuCode为key,sku对象,形成<蜂房code,<skuCode,sku>>这样的数据结构。然后每个铺货点位找到对应的蜂房,查看蜂房内要铺货的sku库存是否满足铺货要求,满足就可以分货,然后将对应sku的库存扣除,不满足就不铺货。

    2. 问题描述
      今天发现了一个问题,运营人员说生成的铺货单的点位不够,但是对应蜂房的库存确实可以满足铺货的。

    3. 问题分析
      通过grep日志发现,同一个蜂房下同一个sku的库存扣减是不连续的。比如库存数突然从224跳到160,那么中间的库存被谁拿走了?猜测是因为别的点位(本应该去它对应的蜂房)也来拿取了蜂房的库存。
      通过review代码发现了问题
      初始化库存的代码如下:

    Map<String, Sku> skuMap = skuReposityMap.get(shop.getEntrepotCode());
    ArrayList<Sku> allSku = Lists.newArrayList();
    allSku.addAll(Safes.of(template.getNormalList()));
    allSku.addAll(Safes.of(template.getHotList()));
    allSku.addAll(Safes.of(template.getColdList()));
    allSku.addAll(Safes.of(template.getDeskList()));
    allSku.addAll(Safes.of(template.getPlugList()));
    for (Sku sku : allSku) {
        //问题就出在这行代码上
        skuMap.put(sku.getCode(), sku);
    }
    skuReposityMap.put(shop.getEntrepotCode(), skuMap);
    

    扣减库存的代码如下

    private List<ShopSkuRelation> filterNecessary(Shop shop, List<ShopSkuRelation> goods, Map<String, Sku> inventory,
                List<Sku> skuList) {
            return goods.stream().filter(shopSkuRelation -> {
                Sku sku = inventory.get(shopSkuRelation.getSkuCode());
                Scale6Decimal originInventory = sku.getInventory();
                logger.info("库房:{},skuCode:{},库存是:{}", shop.getEntrepotCode(), sku.getCode(), originInventory);
                Scale6Decimal result = originInventory.minus(new Scale6Decimal(new BigDecimal(shopSkuRelation.getNum())));
                logger.info("扣减库存,shelfCode是:{},蜂房:{},skuCode是:{},库存是:{},扣减num is {},结果是:{}", shop.getCode(),
                        shop.getEntrepotCode(), sku.getCode(), sku.getInventory(), shopSkuRelation.getNum(), result);
                if (result.isNegative()) {
                    logger.info("skuCode:{},num is :{},repository is {},inventory is{},仓库不满足需求了", sku.getCode(),
                            shopSkuRelation.getNum(), shop.getEntrepotCode(), originInventory);
                    return false;
                } else {
                    //修改库存
                    sku.setInventory(result);
                    return true;
                }
            }).collect(Collectors.toList());
        }
    

    第一段是循环遍历初始化库房-sku库存的数据结构,由于都是每个蜂房查询的sku列表是相同的,这个地方拿到的sku都是从template中get的,然后放到不同的map中去。而在下面修改库存的时候,其实修改的sku对象指向到的是同一份sku实例,本来我们期望的是不同蜂房的sku库存是相互隔离的,但是由于在初始化的时候,不同的蜂房使用了同一份sku,因此就出现了不同的点位扣除是同一份sku的库存

    1. 解决方案
      在初始化的时候,template吐出来的sku集合是一个deep copy就好了,这样就能保证每次遍历拿到的sku是独立的,也能保证即使对sku进行结构性变化,也不会影响到template。

    相关文章

      网友评论

          本文标题:一次Java对象引用使用不当的引起问题

          本文链接:https://www.haomeiwen.com/subject/pkblixtx.html