最蠢的代码

最蠢的代码

/**
 * 插入商品规格信息
 */
private void insertSpeInfo(GoodsDetailVo model, Goods commonFields) {
    Long goodId = commonFields.getId();
    //为商品规格基本信息添加所属商品ID,填充公共字段
    List<GoodsSpecificationVo> goodsSpecificationVos = model.getGoodsSpecificationVos()
            .stream().peek(goodsSpecificationVo -> {
                goodsSpecificationVo.setGoodsId(goodId);
                fillCommonFields(commonFields, goodsSpecificationVo);
            }).collect(Collectors.toList());
    //spcID集合
    List<Long> spcIds = new ArrayList<>();
    //规格值对象集合
    List<GoodsSpecValues> goodsSpecValues = new ArrayList<>();
    //取出规格名与对应的规格值集合
    for (GoodsSpecificationVo goodsSpecificationVo : goodsSpecificationVos) {
        //保存规格名
        GoodsSpecification goodsSpecification = BeanUtil.copyProperties(goodsSpecificationVo, GoodsSpecification.class);
        goodsSpecificationService.save(goodsSpecification);
        //获取规格名ID
        Long spcID = goodsSpecification.getId();
        spcIds.add(spcID);
        List<String> specValue = goodsSpecificationVo.getSpecValue();
        //保存规格值
        for (String sv : specValue) {
            GoodsSpecValues values = new GoodsSpecValues(spcID, sv);
            fillCommonFields(commonFields, values);
            goodsSpecValues.add(values);
        }
        goodsSpecValuesService.saveBatch(goodsSpecValues);
        goodsSpecValues.clear();
    }
    String strIds = listToString(spcIds);
    //拿到规格值和对应ID
    Map<String, Long> spcValIds = goodsSpecValuesService
            .list(Wrappers.<GoodsSpecValues>lambdaQuery().in(GoodsSpecValues::getSpecId, spcIds))
            .stream().collect(Collectors.toMap(GoodsSpecValues::getSpecValue, GoodsSpecValues::getId));
    //获取商品sku集合
    List<GoodsSku> goodsSkus = model.getGoodsSkuVos().stream()
            .map(goodsSkuVo -> {
                GoodsSku goodsSku = BeanUtil.copyProperties(goodsSkuVo, GoodsSku.class);
                fillCommonFields(commonFields, goodsSku);
                goodsSku.setGoodsId(goodId);
                //设置规格名组合ID集合
                goodsSku.setGoodsSpec(strIds);
                //设置规格值组合ID集合
                List<Long> spcValCombinationIds = goodsSkuVo.getGoodsSpecValues().stream()
                        .map(spcValIds::get)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
                goodsSku.setGoodsSpecValue(listToString(spcValCombinationIds));
                return goodsSku;
            })
            .collect(Collectors.toList());
    // 写入商品总库存信息
    model.getGood().setQuantity(goodsSkus.stream().mapToInt(GoodsSku::getQuantity).sum());
    updateById(model.getGood());
    //保存sku
    goodsSkuService.saveBatch(goodsSkus);
}

先大概解析一下这段代码的作用

它接受一个GoodsDetailVo对象和一个Goods对象作为参数,然后从GoodsDetailVo中提取商品规格信息并保存到数据库中。

具体而言,该代码执行以下主要步骤:

  1. GoodsDetailVo对象中获取商品规格信息,包括规格名、规格值、SKU(库存单位)等。
  2. 为商品规格基本信息添加所属商品ID和填充公共字段(例如创建时间、更新时间等)。
  3. 保存规格名到数据库,并获取规格名的ID。
  4. 保存规格值到数据库,并使用规格名的ID关联规格值。
  5. 将规格值和对应的ID存储在spcValIds映射中,用于后续的关联。
  6. 处理商品SKU信息,设置商品ID、规格名组合ID集合、规格值组合ID集合等。
  7. 计算并更新商品总库存信息。
  8. 保存商品SKU信息到数据库。

存在的主要问题

  • 在循环中使用了数据库操作:在循环内部进行数据库的保存操作,会导致频繁的数据库访问,影响性能。

    for (GoodsSpecificationVo goodsSpecificationVo : goodsSpecificationVos) {
        //保存规格名
        GoodsSpecification goodsSpecification = BeanUtil.copyProperties(goodsSpecificationVo, GoodsSpecification.class);
        goodsSpecificationService.save(goodsSpecification);
        //获取规格名ID
        Long spcID = goodsSpecification.getId();
        spcIds.add(spcID);
        List<String> specValue = goodsSpecificationVo.getSpecValue();
        //保存规格值
        for (String sv : specValue) {
            GoodsSpecValues values = new GoodsSpecValues(spcID, sv);
            fillCommonFields(commonFields, values);
            goodsSpecValues.add(values);
        }
        goodsSpecValuesService.saveBatch(goodsSpecValues);
        goodsSpecValues.clear();
    }
    
    • 在这里,循环调用 goodsSpecificationService.save(goodsSpecification);依次逐个保存规格名,之后再将获取到规格名ID逐个插入到规格值中,即这段代码GoodsSpecValues values = new GoodsSpecValues(spcID, sv);
    • 之后又犯了同样的错误,又一次在循环中来了数据库IO操作goodsSpecValuesService.saveBatch(goodsSpecValues);
  • 重复清空集合:在保存规格值的部分,使用了一个清空集合的操作goodsSpecValues.clear(),但该操作在每次循环中执行,并不需要如此频繁地清空集合。可以将清空集合的操作移到循环外部,在循环结束后进行一次清空即可。

goodsSpecValuesService.saveBatch(goodsSpecValues);
goodsSpecValues.clear();
  • 方法调用顺序问题:在更新商品总库存信息的部分,调用了updateById(model.getGood())来更新商品信息,但是该方法的调用在保存SKU之前,可能导致库存信息不准确。
// 写入商品总库存信息
model.getGood().setQuantity(goodsSkus.stream().mapToInt(GoodsSku::getQuantity).sum());
updateById(model.getGood());
//保存sku
goodsSkuService.saveBatch(goodsSkus);
  • 没必要的数据库查询:

    //拿到规格值和对应ID
        Map<String, Long> spcValIds = goodsSpecValuesService
                .list(Wrappers.<GoodsSpecValues>lambdaQuery().in(GoodsSpecValues::getSpecId, spcIds))
                .stream().collect(Collectors.toMap(GoodsSpecValues::getSpecValue, GoodsSpecValues::getId));
    
     //设置规格值组合ID集合
    List<Long> spcValCombinationIds = goodsSkuVo.getGoodsSpecValues().stream()
            .map(spcValIds::get)
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    goodsSku.setGoodsSpecValue(listToString(spcValCombinationIds));
    
    public String listToString(List<Long> ids) {
        return ids.stream()
                .map(String::valueOf)
                .collect(Collectors.joining(","));
    }
    
    • 其实这次数据库查询是完全不必要的,应该直接从已经保存过后的goodsSpecValues局部变量中去筛选数据即可,不过此时的goodsSpecValues也不是完全的,原因就在于第一个问题中我采用在循环中保存规格值
    • 应该在构造这个spcValIds集合的时候就直接将value值转为String类型
  • 代码可读性:方法代码逻辑过多,应该对不同表不同数据的插入做拆分,抽离逻辑,抽离成单独的小方法,之后再拼接在一起增强可读性

优化后的代码

这是优化过后的最终版本,中间还有两次优化就不作展示了

private void insertSpeInfo(GoodsDetailVo model, Goods commonFields) {
    Long goodId = commonFields.getId();

    //为商品规格基本信息添加所属商品ID,填充公共字段,获取Vo对象
    List<GoodsSpecificationVo> goodsSpecificationVos = model.getGoodsSpecificationVos()
            .stream().peek(goodsSpecificationVo -> {
                goodsSpecificationVo.setGoodsId(goodId);
                fillCommonFields(commonFields, goodsSpecificationVo);
            }).collect(Collectors.toList());

    //保存规格名
    List<GoodsSpecification> goodsSpecifications = insertGoodsSpecification(goodsSpecificationVos);

    //规格名ID集合
    List<Long> spcIds = goodsSpecifications.stream().map(GoodsSpecification::getId).collect(Collectors.toList());

    //保存规格值
    List<GoodsSpecValues> goodsSpecValues = insertGoodsSpecValue(commonFields, goodsSpecificationVos, spcIds);

    // 保存sku
    List<GoodsSkuVo> goodsSkuVos = model.getGoodsSkuVos()
            .stream().peek(goodsSkuVo -> {
                fillCommonFields(commonFields, goodsSkuVo);
                goodsSkuVo.setGoodsId(goodId);
            })
            .collect(Collectors.toList());
    String strIds = listToString(spcIds);
    List<GoodsSku> goodsSkus = insertGoodsSku(strIds, goodsSpecValues, goodsSkuVos);

    // 写入商品总库存信息
    insertTotalQuantity(model, goodsSkus);
}

//保存商品的库存信息
private void insertTotalQuantity(GoodsDetailVo model, List<GoodsSku> goodsSkus) {
    //计算总库存
    int totalQuantity = goodsSkus.stream().mapToInt(GoodsSku::getQuantity).sum();
    Goods good = model.getGood();
    good.setQuantity(totalQuantity);
    //更新商品信息
    update(good);
}

//保存商品的sku信息
private List<GoodsSku> insertGoodsSku(String speIds, List<GoodsSpecValues> goodsSpecValues,
                                      List<GoodsSkuVo> goodsSkuVos) {
    // 拿到规格值和对应ID
    Map<String, String> spcValIds = goodsSpecValues.stream()
            .collect(Collectors.toMap(GoodsSpecValues::getSpecValue,
                    goodsSpecValue -> String.valueOf(goodsSpecValue.getId())));

    List<GoodsSku> goodsSkus = goodsSkuVos.stream()
            .map(goodsSkuVo -> {
                GoodsSku goodsSku = BeanUtil.copyProperties(goodsSkuVo, GoodsSku.class);
                // 设置规格名组合ID集合
                goodsSku.setGoodsSpec(speIds);
                // 设置规格值组合ID集合
                goodsSku.setGoodsSpecValue(
                        goodsSkuVo.getGoodsSpecValues().stream()
                                .map(spcValIds::get)
                                .collect(Collectors.joining(","))
                );
                return goodsSku;
            })
            .collect(Collectors.toList());
    //保存sku
    goodsSkuService.saveBatch(goodsSkus);
    return goodsSkus;
}

//保存商品的规格值信息
private List<GoodsSpecValues> insertGoodsSpecValue
        (Goods commonFields, List<GoodsSpecificationVo> goodsSpecificationVos, List<Long> spcIds) {
    //规格值列表
    List<GoodsSpecValues> goodsSpecValues = new ArrayList<>();
    int i = 0;
    for (GoodsSpecificationVo goodsSpecificationVo : goodsSpecificationVos) {
        Long spcID = spcIds.get(i++);
        List<String> specValue = goodsSpecificationVo.getSpecValue();
        List<GoodsSpecValues> specValuesList = specValue.stream().map(sv -> {
            GoodsSpecValues values = new GoodsSpecValues(spcID, sv);
            fillCommonFields(commonFields, values);
            return values;
        }).collect(Collectors.toList());
        goodsSpecValues.addAll(specValuesList);
    }

    goodsSpecValuesService.saveBatch(goodsSpecValues);
    return goodsSpecValues;
}

//保存商品的规格名信息
private List<GoodsSpecification> insertGoodsSpecification
                                                  (List<GoodsSpecificationVo> goodsSpecificationVos) {
List<GoodsSpecification> goodsSpecifications = BeanUtil.copyToList(goodsSpecificationVos,                                                                                             GoodsSpecification.class);
    goodsSpecificationService.saveBatch(goodsSpecifications);
    return goodsSpecifications;
}

以下是对代码进行优化的几个点

  • 增强可读性:对方法的整体做了拆分,对于不同的数据的插入拆分成了不同的独立小方法,增强了可读性

  • 减少数据库访问次数:将数据库操作尽量集中在一起,减少频繁的数据库访问。

//保存商品的规格值信息
private List<GoodsSpecValues> insertGoodsSpecValue
        (Goods commonFields, List<GoodsSpecificationVo> goodsSpecificationVos, List<Long> spcIds) {
    //规格值列表
    List<GoodsSpecValues> goodsSpecValues = new ArrayList<>();  //定义一个局部变量用来存储规格值
    int i = 0;
    for (GoodsSpecificationVo goodsSpecificationVo : goodsSpecificationVos) {
        Long spcID = spcIds.get(i++);
        List<String> specValue = goodsSpecificationVo.getSpecValue();
        List<GoodsSpecValues> specValuesList = specValue.stream().map(sv -> {
            GoodsSpecValues values = new GoodsSpecValues(spcID, sv);
            fillCommonFields(commonFields, values);
            return values;
        }).collect(Collectors.toList());
        goodsSpecValues.addAll(specValuesList);
    }

    goodsSpecValuesService.saveBatch(goodsSpecValues);//批量一次性保存规格值
    return goodsSpecValues;
}

//保存商品的规格名信息
private List<GoodsSpecification> insertGoodsSpecification
                                                  (List<GoodsSpecificationVo> goodsSpecificationVos) {
List<GoodsSpecification> goodsSpecifications = 
    BeanUtil.copyToList(goodsSpecificationVos,GoodsSpecification.class);                                   
    goodsSpecificationService.saveBatch(goodsSpecifications);     //批量一次性保存规格名信息     
    return goodsSpecifications;                       
}
  • 优化规格值和对应ID的获取方式:使用已批量保存的规格之集合获取规格值和对应ID的映射关系。
private List<GoodsSku> insertGoodsSku(String speIds, List<GoodsSpecValues> goodsSpecValues,
                                      List<GoodsSkuVo> goodsSkuVos) {
    // 拿到规格值和对应ID
    Map<String, String> spcValIds = goodsSpecValues.stream()   //减少了不必要的数据库查询
            .collect(Collectors.toMap(GoodsSpecValues::getSpecValue,
                goodsSpecValue -> String.valueOf(goodsSpecValue.getId()))); //直接将value值转为string类型

    List<GoodsSku> goodsSkus = goodsSkuVos.stream()
            .map(goodsSkuVo -> {
                GoodsSku goodsSku = BeanUtil.copyProperties(goodsSkuVo, GoodsSku.class);
                // 设置规格名组合ID集合
                goodsSku.setGoodsSpec(speIds);
                // 设置规格值组合ID集合
                goodsSku.setGoodsSpecValue(
                        goodsSkuVo.getGoodsSpecValues().stream()
                                .map(spcValIds::get)
                                .collect(Collectors.joining(",")) //减少了方法的调用
                );
                return goodsSku;
            })
            .collect(Collectors.toList());
    //保存sku
    goodsSkuService.saveBatch(goodsSkus);
    return goodsSkus;
}
  • 更新商品总库存信息:调整更新商品信息的位置,确保在保存SKU之后更新商品总库存信息。
// 保存sku
insertGoodsSku(strIds, goodsSpecValues, goodsSkuVos);
// 写入商品总库存信息
insertTotalQuantity(model, commonFields);
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值