Java开发中要避免在for循环中进行数据库的频繁访问,如果数据量大,那么for循环里就是频繁进行数据库操作,带来很大的IO开销,从而降低了应用的性能和响应的速度。下面通过举正反两个例子验证一下。
正例:
// 从数据库中获取产品数据
List<SpuInfoEntity> spuInfoEntities = spuInfoService.getBaseMapper().selectList(Wrappers.lambdaQuery(SpuInfoEntity.class)
.select(SpuInfoEntity::getId, SpuInfoEntity::getBrandId));
//将产品id收集到一个Set集合(防重复)
Set<Long> spuIds = spuInfoEntities.stream().map(SpuInfoEntity::getId).collect(Collectors.toSet());
//根据产品id查询该产品所有属性值
Map<Long, List<ProductAttrValueEntity>> productAttrValuesMap = productAttrValueMapper.selectList(Wrappers.lambdaQuery(ProductAttrValueEntity.class)
.in(ProductAttrValueEntity::getSpuId, spuIds))
.stream()
.collect(Collectors.groupingBy(ProductAttrValueEntity::getSpuId));
//根据产品id查询该商品信息
Map<Long, SkuInfoEntity> skuInfoMap = skuInfoMapper.selectList(Wrappers.lambdaQuery(SkuInfoEntity.class)
.in(SkuInfoEntity::getSpuId, spuIds))
.stream()
.collect(Collectors.toMap(SkuInfoEntity::getSpuId, Function.identity()));
//根据产品id查询该品牌信息
Map<Long, Brand> brandMap = brandMapper.selectBatchIds(spuInfoEntities.stream().map(SpuInfoEntity::getBrandId).collect(Collectors.toSet()))
.stream()
.collect(Collectors.toMap(Brand::getBrandId, Function.identity()));
//根据产品id查询产品图片信息
Map<Long, List<SpuImagesEntity>> spuImagesMap = spuImagesMapper.selectList(Wrappers.lambdaQuery(SpuImagesEntity.class)
.in(SpuImagesEntity::getSpuId, spuIds))
.stream()
.collect(Collectors.groupingBy(SpuImagesEntity::getSpuId));
// 构建 SpuInfoVo 列表
List<SpuInfoVo> spuInfoVoList = spuInfoEntities.stream()
//使用过滤器保留符合条件的产品,将产品中不符合条件的剔除掉
.filter(spuInfo -> {
List<ProductAttrValueEntity> attrValues = productAttrValuesMap.getOrDefault(spuInfo.getId(), Collections.emptyList());
boolean hasThresholds = attrValues.stream().anyMatch(attrValue -> "内存大小".equals(attrValue.getAttrName()));
boolean hasChargeStyle = attrValues.stream().anyMatch(attrValue -> "颜色".equals(attrValue.getAttrName()));
return hasThresholds && hasChargeStyle;
})
.map(spuInfo -> {
SpuInfoVo spuInfoVo = new SpuInfoVo();
BeanUtils.copyProperties(spuInfo, spuInfoVo);
List<ProductAttrValueEntity> attrValues = productAttrValuesMap.getOrDefault(spuInfo.getId(), Collections.emptyList());
attrValues.forEach(attrValue -> {
switch (attrValue.getAttrName()) {
case "内存大小":
String attrValue1 = attrValue.getAttrValue();
List<String>attrValueList=new ArrayList<>();
if(attrValue1!=null&&attrValue1.contains(",")){
attrValueList.addAll(Arrays.asList(attrValue1.split(",")));
}else {
attrValueList.add(attrValue1);
}
spuInfoVo.setThresholds(attrValueList);
break;
case "颜色":
spuInfoVo.setChargeStyle(attrValue.getAttrValue());
break;
}
});
//从map取出对应产品id的商品信息
SkuInfoEntity skuInfo = skuInfoMap.get(spuInfo.getId());
spuInfoVo.setPrice(skuInfo == null ? BigDecimal.ZERO : skuInfo.getPrice());
//从map取出对应产品id的品牌信息
Brand brand = brandMap.get(spuInfo.getBrandId());
spuInfoVo.setBrandName(brand == null ? "" : brand.getName());
List<SpuImagesEntity> images = spuImagesMap.getOrDefault(spuInfo.getId(), Collections.emptyList());
if (!images.isEmpty()) {
spuInfoVo.setImgUrl(images.get(0).getImgUrl());
}
return spuInfoVo;
}).collect(Collectors.toList());
经测试,共耗时1956毫秒
反例:
LambdaQueryWrapper<SpuInfoEntity>queryWrapper=Wrappers.lambdaQuery();
queryWrapper.select(SpuInfoEntity::getId,SpuInfoEntity::getBrandId);
List<SpuInfoEntity> spuInfoEntities = spuInfoService.getBaseMapper().selectList(queryWrapper);
List<SpuInfoVo>spuInfoVoList =new ArrayList<>();
for (SpuInfoEntity spuInfo : spuInfoEntities) {
SpuInfoVo spuInfoVo=new SpuInfoVo();
BeanUtils.copyProperties(spuInfo,spuInfoVo);
LambdaQueryWrapper<ProductAttrValueEntity>productAttrValueWrapper=Wrappers.lambdaQuery();
productAttrValueWrapper.select(ProductAttrValueEntity::getSpuId,ProductAttrValueEntity::getAttrName,ProductAttrValueEntity::getAttrValue);
productAttrValueWrapper.eq(ProductAttrValueEntity::getAttrName,"颜色");
productAttrValueWrapper.eq(ProductAttrValueEntity::getSpuId,spuInfo.getId());
ProductAttrValueEntity attrValue = productAttrValueMapper.selectOne(productAttrValueWrapper);
if(attrValue==null){
continue;
}
String attrValue1 = attrValue.getAttrValue();
List<String>attrValues=new ArrayList<>();
if(attrValue1!=null&&attrValue1.contains(",")){
attrValues.addAll(Arrays.asList(attrValue1.split(",")));
}else {
attrValues.add(attrValue1);
}
spuInfoVo.setThresholds(attrValues);
LambdaQueryWrapper<ProductAttrValueEntity>productAttrValueWrapper2=Wrappers.lambdaQuery();
productAttrValueWrapper2.select(ProductAttrValueEntity::getSpuId,ProductAttrValueEntity::getAttrName,ProductAttrValueEntity::getAttrValue);
productAttrValueWrapper2.eq(ProductAttrValueEntity::getAttrName,"内存大小");
productAttrValueWrapper2.eq(ProductAttrValueEntity::getSpuId,spuInfo.getId());
ProductAttrValueEntity attrValue2 = productAttrValueMapper.selectOne(productAttrValueWrapper2);
if(attrValue2==null){
continue;
}
spuInfoVo.setChargeStyle(attrValue2.getAttrValue());
SkuInfoEntity skuInfoEntity = skuInfoMapper.selectOne(new LambdaQueryWrapper<SkuInfoEntity>().select(SkuInfoEntity::getSkuId,
SkuInfoEntity::getSpuId, SkuInfoEntity::getPrice).eq(SkuInfoEntity::getSpuId,spuInfo.getId()).orderByAsc(SkuInfoEntity::getSkuId).last("LIMIT 1"));
spuInfoVo.setPrice(skuInfoEntity==null?BigDecimal.ZERO:skuInfoEntity.getPrice());
Brand brand = brandMapper.selectById(spuInfo.getBrandId());
spuInfoVo.setBrandName(brand==null?"":brand.getName());
List<SpuImagesEntity> spuImagesEntities = spuImagesMapper.selectList(new LambdaQueryWrapper<SpuImagesEntity>().eq(SpuImagesEntity::getSpuId, spuInfo.getId()));
spuInfoVo.setImgUrl(spuImagesEntities.get(0).getImgUrl());
spuInfoVoList.add(spuInfoVo);
}
反例在for循环中访问数据库进行查询操作,经测试,共耗时124546毫秒,即2分多钟,这个执行时间堪称灾难级。
通过上方正反两个例子说明,在实际开发中,在避免在for循环里进行大量的数据库访问,正确的方式是进行一次查询,将id收集成一个集合,然后再根据id逐个查询,并保存在map集合中,id作为map集合的key,取值时根据id这个key,取出对应的value,如何使用请参考上方的正例。