Mybatis-Plus多表查询-拼接对象属性优化
背景:
用户表: userId、username
帖子表: id、userId、content
需要给前端返回一个帖子VO列表List<ResultVO>
,VO中的字段有,帖子的内容content、和用户的信息对象User
一般思路
先查询帖子表,然后for循环遍历帖子表,根据每个VO对象中的userId,再去查询User表,然后把User对象拼接到VO对象中
//创建结果对象
List<ResultVO> result=new ArrayList<>();
//获取帖子
List<TZ> tzList=tzService.seletAll();
//遍历帖子,把帖子加入到结果对象, 并插入用户对象
for(TZ tz:tzList){
ResultVO resultVo=new ResultVO();
resultVO.setTZ=tz;
Integer userId=tz.getUserId();
User user=userService.selectById(userId);
resultVO.setUser(user);
reuslt.add(resultVO);
}
return result;
缺点:
查询帖子:1次
查询用户:n次(一个帖子就要查一个用户)
查询次数过多,性能过慢,而且一个用户可能有多个帖子,一条用户数据可能被查询多次,不合理。
由于查询次数过多,会消耗连接池中的链接,并且查询数据库也是需要网络连接流量的
优化后的思路
简述:一次性查出帖子,然后把帖子中的userId提取出来作为一个userId列表,最后在根据这个userId列表一次性把userId对应的用户查出来作为一个User列表,最后根据userId把帖子列表和User列表拼接起来,这样就能做到只用查询数据库2次
详细描述:
先查询帖子表,拿到帖子对象列表List<TZ> tzList;
——查询数据库1次
然后在帖子对象列表中,提取用户id集合 Set<Long> userIdList;
然后根据用户id集合userIdList
查询数据库,得到用户列表后对用户列表进行分组,得到一个id和用户对象User的映射Map<Long,List<User>> userIdListMap
——查询数据1次
这里其实也可以使用的是Map<Long,User>的结构,这里使用Map<User,List<User>> 是为了防止数据库中有数据错误,导致一个id有多个用户
分组的目的也是为了简化代码开发,如果不分组的话,要有两层for循环,遍历帖子列表后,再遍历用户列表,把对应的用户拼接上。
而分组后,把用户id作为key,可以直接使用containsKey()方法,快速早到用户对象,时间为O(1)
最后遍历把对应的用户信息拼接上去即可
//创建结果对象
List<ResultVO> result=new ArrayList<>();
//获取帖子
List<TZ> tzList=tzService.seletAll();
//获取用户id集合
Set<Long> userIdList=tzList.stream().map(TZ::getUserId).collect(Colletions.toSet());
//获取用户集合
List<User> userList=userService.selectByIds(userIdList);
//根据id分组
Map<Long, List<User>> userIdUserListMap =userList.stream().collect(Collectors.groupingBy(User::getId));
//拼接信息
result=tzList.stream().map(tz->{
ResultVO resultVO=new ResultVO();
Long userId=tz.getUserId();
User user=null;
if(userIdUserListMap.containsKey(userId)){
user = userIdUserListMap.get(userId).get(0);
}
resultVO.setUserVO(user);
return resultVO;
}).collect(Collectors.toList());
/*
**不分组的写法
for(TZ tz:tzList){
ResultVO resultVo=new ResultVO();
resultVO.setTZ=tz;
//对比用户id,进行拼接
Integer userId=tz.getUserId();
for(User user:UserList){
if(user.getId()==userId){
resultVO.setUser(user);
}else{
resultVO.setUser(null);
}
}
reuslt.add(resultVO);
}
*/
return result;