前言
大家好,我是刺客阿七,该账号主要记录我工作以来的一些经验,毕业工作的第一篇文章,写的可能不太好,希望大家指正,一起进步学习。
正文
需求举例
举一个比较简单的需求,众所周知,在电商项目管理平台肯定会有一个商品列表,商品列表会查询出商品数据和一些和商品相关的数据,这里以商品的供应商名称为例,但是商品表一般只会存供应商的id,这个时候我们还需要查询供应商的数据,看到这大家肯定会想,这还不简单,直接关联查询一下不就可以了吗,但是没这么简单,因为我们这个系统是一个微服务项目,商品模块和用户模块是不同的服务,对应的数据库也是不同的,所以得通过Feign来进行数据传递,但是这些对于本文来说都不重要,我们主要学习这个思想,以下是三种实现方式。
实体
1 商品实体部分属性和供应商实体部分属性 `
package com.decent.manager.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 商品测试属性
*
* @author lhh
* @date 2024/4/1 14:39
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
/**
* 商品id
*/
private Long id;
/**
* 商品名称
*/
private String productName;
/**
* 供应商id
*/
private Long supplierId;
}
package com.decent.manager.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 供应商测试属性
*
* @author lhh
* @date 2024/4/1 14:39
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Supplier {
/**
* 供应商id
*/
private Long id;
/**
* 供应商名称
*/
private String supplierName;
}
2 返回给前端的vo
package com.decent.manager.vo;
import com.decent.manager.entity.Product;
import lombok.*;
/**
* 商品VO
*
* @author lhh
* @date 2024/4/1 15:42
*/
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductVO extends Product {
/**
* 供应商名称
*/
private String supplierName;
public ProductVO(Long id, String productName, Long supplierId) {
super(id, productName, supplierId);
}
}
实现一
遍历整个商品集合,通过循环调用fegin依次给每个商品的供应商赋值。
// 模拟商品数据
List<ProductVO> productList = Arrays.asList(
new ProductVO(1L, "商品1", 1L),
new ProductVO(2L, "商品2", 2L),
new ProductVO(3L, "商品3", 3L));
// 遍历商品,调用Feign查询,获取供应商数据然后通过id赋值
productList.forEach(product -> {
// 1 通过商品的供应商id,调用fegin查询该供应商的数据,因为没有fegin,new个对象假装查到了
Supplier supplier = new Supplier();
product.setSupplierName(supplier.getSupplierName());
});
这样一看,功能确实没问题,但是大家都知道,调用fegin(或者是执行sql语句,因为要建立数据库连接)是比较消耗性能的,然后我还在循环里面调用,这显然是及其消耗性能的,所以,我们想想能不能只调用一次fegin或者数据库呢?
实现二
遍历整个商品集合,把所有供应商数据一次性查出来,然后通过循环供应商遍历赋值。
// 模拟商品数据
List<ProductVO> productList = Arrays.asList(
new ProductVO(1L, "商品1", 1L),
new ProductVO(2L, "商品2", 2L),
new ProductVO(3L, "商品3", 3L));
// 通过fegin一次性把所有供应商数据查出来
List<Supplier> supplierList = Arrays.asList(
new Supplier(1L, "供应商1"),
new Supplier(2L, "供应商2"),
new Supplier(3L, "供应商3"));
// 遍历商品,调用Feign查询,获取供应商数据然后通过id赋值
productList.forEach(product -> {
supplierList.forEach(supplier -> {
product.setSupplierName(supplier.getSupplierName());
});
});
这样一看,确实减少了fegin的调用或者sql的执行次数,但是仔细一看,双层for循环,时间复杂度n*n?这样显然还不够好。
实现三
沿用实现二的代码,然后将供应商数据转为map,再通过map的get方法获取供应商数据,这样时间复杂度就是n了。
// 模拟商品数据
List<ProductVO> productList = Arrays.asList(
new ProductVO(1L, "商品1", 1L),
new ProductVO(2L, "商品2", 2L),
new ProductVO(3L, "商品3", 3L));
// 通过fegin一次性把所有供应商数据查出来
List<Supplier> supplierList = Arrays.asList(
new Supplier(1L, "供应商1"),
new Supplier(2L, "供应商2"),
new Supplier(3L, "供应商3"));
Map<Long, String> supplierMap = supplierList.stream().collect(Collectors.toMap(Supplier::getId,
Supplier::getSupplierName));
// 遍历商品,调用Feign查询,获取供应商数据然后通过id赋值
productList.forEach(product -> {
product.setSupplierName(supplierMap.get(product.getSupplierId()));
});
}