业务场景
我们先来从场景入手,具体的业务是这样的:我们需要从某的省的id去查询这个省份所有的县区,至于什么是县区呢?在DB中我们是这样定义的,也就是字段level = 3 的时候,就代表一个县的信息,然后呢:我们需要查询某个省份的所有县区的项目数,一个县区下可能有很多项目,也可能没有项目信息;
返回格式
{
"msg": "操作成功",
"code": 200,
"data": [
{
"pid": 2,
"id": 4,
"areaCode": "540121",
"projectCount": 1,
"areaName": "某某县",
"investMoney": 0,
"level": 3,
"listMigSupportProjectItemVo": null,
"migSupportProjectList": [
{
"areaCode": "540121",
"name": "测试01",
"reservoirs": "1",
"projectNum": "2",
"investPlan": "20000.0",
"type": "散居移民基础设施完善",
"status": "plan",
"acceptTime": null,
"unitAfterHandover": null
}
]
},
{
"pid": 23,
"id": 24,
"areaCode": "542221",
"projectCount": 3,
"areaName": "乃某某某某县",
"investMoney": 0,
"level": 3,
"listMigSupportProjectItemVo": null,
"migSupportProjectList": [
{
"areaCode": "542221",
"name": "项目A",
"reservoirs": "水库A",
"projectNum": "项目批准文号A",
"investPlan": "1000000.0",
"type": "就业创业能力建设",
"status": "implemented",
"acceptTime": "2023-02-01",
"unitAfterHandover": "单位B"
},
{
"areaCode": "542221",
"name": "项目B",
"reservoirs": "水库B",
"projectNum": "项目批准文号B",
"investPlan": "2000000.0",
"type": "类型2",
"status": "implemented",
"acceptTime": "2024-03-01",
"unitAfterHandover": "孤帆候风进"
},
{
"areaCode": "542221",
"name": "项目C",
"reservoirs": "水库C",
"projectNum": "项目批准文号C",
"investPlan": "3000000.0",
"type": "类型3",
"status": "implementation",
"acceptTime": null,
"unitAfterHandover": null
}
]
},
{
"pid": 23,
"id": 25,
"areaCode": "542222",
"projectCount": 2,
"areaName": "扎囊县",
"investMoney": 0,
"level": 3,
"listMigSupportProjectItemVo": null,
"migSupportProjectList": [
{
"areaCode": "542222",
"name": "项目D",
"reservoirs": "水库D",
"projectNum": "项目批准文号D",
"investPlan": "4000000.0",
"type": "类型1",
"status": "plan",
"acceptTime": "2026-03-01",
"unitAfterHandover": "单位D"
},
{
"areaCode": "542222",
"name": "项目F",
"reservoirs": "水库F",
"projectNum": "项目批准文号F",
"investPlan": "6000000.0",
"type": "类型2",
"status": "plan",
"acceptTime": null,
"unitAfterHandover": null
}
]
},
{
"pid": 23,
"id": 30,
"areaCode": "542227",
"projectCount": 2,
"areaName": "某某1县",
"investMoney": 0,
"level": 3,
"listMigSupportProjectItemVo": null,
"migSupportProjectList": [
{
"areaCode": "542227",
"name": "项目E",
"reservoirs": "水库E",
"projectNum": "项目批准文号E",
"investPlan": "5000000.0",
"type": "类型2",
"status": "plan",
"acceptTime": "2023-07-08",
"unitAfterHandover": "规范打广告"
},
{
"areaCode": "542227",
"name": "1111",
"reservoirs": "1",
"projectNum": "1",
"investPlan": "10000.0",
"type": null,
"status": "plan",
"acceptTime": null,
"unitAfterHandover": null
}
]
}
]
}
原始代码
具体的话呢,会返回这样的一个Json格式,可以看出,没有项目的县是不会被返回的,并且查询出来的项目信息回做一个合并的统计,具体的场景就是查询所有某个省所有level为3的信息,然后拿到它的区域编码然后去项目表中查询项目信息,也就是我们要执行很多查询的sql,根据区域编码去查询项目集合(每一个县区的编码都不一样),接下来看一下我们开始写的代码
public List<MigSupportProjectScreenVo> selectAllisBuildProjectByLowestLevel(MigSupportScreenBo migSupportScreenBo) {
//先查询所有level = 3 的区域数据
List<MigSupportProjectScreenVo> migSupportProjectScreenVos = screenSupportMapper.selectByLowestLevel();
migSupportProjectScreenVos.forEach(item -> {
item.setMigSupportProjectList(selectProjectListByid(item.getAreaCode(), migSupportScreenBo.getType()));
});
ArrayList<MigSupportProjectScreenVo> res = new ArrayList<>();
migSupportProjectScreenVos.forEach(item->{
if (item.getMigSupportProjectList().size()!=0){
res.add(item);
}
});
return res;
}
//根据区域的code查询一个项目集合
private List<MigSupportProject> selectProjectListByid(String code, Integer type) {
return migSupportProjectMapper.selectProjectType(code, type);
}
是单线程的代码,在循环里面调用sql,然后在APIFox中进行测试,在清除了Mybatis缓存的情况下
优化后的代码
经过优化,我们用了CompletableFuture进行性能的优化
public List<MigSupportProjectScreenVo> selectAllisBuildProjectByLowestLevel(MigSupportScreenBo migSupportScreenBo) {
// 先查询所有level = 3 的区域数据
List<MigSupportProjectScreenVo> migSupportProjectScreenVos = screenSupportMapper.selectByLowestLevel();
// 使用 CompletableFuture 异步执行 selectProjectListByid 方法
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (MigSupportProjectScreenVo item : migSupportProjectScreenVos) {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
item.setMigSupportProjectList(selectProjectListByid(item.getAreaCode(), migSupportScreenBo.getType()));
return null;
});
futures.add(future);
}
// 等待所有异步任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 过滤掉没有项目的 MigSupportProjectScreenVo 对象
List<MigSupportProjectScreenVo> res = migSupportProjectScreenVos.stream()
.filter(item -> item.getMigSupportProjectList().size() != 0)
.collect(Collectors.toList());
return res;
}
使用forkerJoinPool的默认线程池进行优化,没有使用自定义线程池.
由此可见,速度肉眼可见的提升了!