业务背景为:开发一个刷题平台,题目分类表记录题目分类例如:“JAVA基础”,“数据库基础”。
题目标签表记录题目标签例如:“索引”,“事务”,分类与标签为多对多关系,创建中间表对两表进行关联。
现在需要查询出所有题目分类以及分类相关的标签,将其存入缓存中并展示。如分类1:标签1,标签2,
分类2:标签3,标签4,原接口实现为传入一个分类id
- 查询该分类所有下级分类;
- 通过下级分类ID进入中间表去查询分类所关联的标签;
- 再通过标签的id查询出实际的标签;
该过程中因数据量不大,在第二步时我选择使用循环查询分类相关的标签,查询后放入缓存。
这里用一段简易代码来进行展示.
Public List<CategoryBO> QueryLabel(int CategoryId){
//获取下级分类
List<Category> categorys = GetLowLevelCategory(CategoryId);
List<CategoryBO> categoryBOs = new ArrayList<CategoryBO>();
//原实现
for(Category category :categorys){
CategoryBO categoryBo = new CategoryBO();
List<Label> labels = GetLabels(category.getCategoryId());
//将集合放入CategoryBO对象中
categoryBO.setLabelList(labels);
categoryBO.setCategoryId(category.getCategoryId());
categoryBOs.add(categoryBO);
}
return categoryBOs;
}
原实现中在循环中去查询标签,查完一个继续查询第二个。这样的效率是很低下的。
查询标签集合这一步是没有同步需求的,可以并发执行。
这个时候可以引入多线程,以及进行异步查询来优化这些操作。这里选择CompletableFuture进行实现。
Public List<CategoryBO> QueryLabel(int CategoryId){
List<CategoryBO> categoryBOs = new ArrayList<CategoryBO>();
List<CompletableFuture<List<Label>>> completableFutureList = categorys.stream()
.map(category ->
//通过下方方法提交异步任务,其中参数一为函数,传入我们要执行的方法任务,
//参数二为自定义重写的线程池,只修改了打印的内容,用来标识是哪个线程池在进行执行任务、
CompletableFuture.supplyAsync(
() -> GetLabels(category.getCategoryId()),
labelThreadPool)
).collect(Collectors.toList());
completableFutureList.forEach(future -> {
try {
//获取任务执行后返回的结果
List<Label> result= future.get();
//进行数据处理,将数据集合返回
…………
// 或者在上方传入的函数中直接进行数据处理,将需要的最终数据直接返回。
} catch (Exception e) {
e.printStackTrace();
}
});
}
同时CompletableFuture也可以进行异步回调,多任务组合,达成类似“同步”意义的效果,这里暂不作举例。