之前在开发过程中,遇到了这样的一个业务场景,需要通过传进来的一个id列表list去查询一个list数据,然后再对每一个数据做相应的业务处理,那时候刚出来工作,第一时间想到的是用for循环去遍历这个id列表,然后一个一个去根据id把对应的数据查出来,再做处理。
乍一看这样处理没什么问题,但是当传进来的id列表很大的时候,对数据库的操作就太频繁了,假如id列表有10个数据,就得查询10次数据库,当三个用户同时访问得时候,就得查询30次,那在高并发的情况下数据库就炸了。后来写完再代码回看的时候,发现这样有点傻,就想到了先通过批量查询,把List<id>作为一个查询条件通过sql的 in 方法先去一次过把数据全查出来,然后把查出来的List<>数据通过Stream转为map,再通过遍历id列表,以id为key去一个一个拿map中的数据,这样就可以大大减低数据库的访问了。
话不多说,上代码:
模拟一个传进来的id列
List<Integer> ids = Arrays.asList(1,2,4,5);
原来的思路:
for (int i = 0; i < ids.size(); i++) {
//遍历查询User
User user = userMapper.getById(ids.get(i));
/*
* 这里写处理业务
* */
}
mapper查询语句:
@Select("select * from user where id = #{id}")
User getById(@Param("id") Integer id);
没接触Stream之前,我基本上遇到这种查询多个的,都这样写,直到那个风和日丽的下午,我去看了java8的新特性
新思路写法;
先一次性批量查询出所有的数据
List<User> userList = userMapper.getByIds(ids);
mapper语句:
@Select({
"<script>" +
"select * from user where id in " +
"<foreach item = 'item' index = 'index' collection = 'ids' open='(' separator=',' close=')'>" +
"#{item}" +
"</foreach>"+
"</script>"})
List<User> getByIds(@Param("ids") List<Integer> ids);
再把查询出来的List<User>转为以id为key的map:
Map<Integer, User> userMap = userList.parallelStream().collect(Collectors.toMap(User :: getId, u -> u, (u1, u2) -> u1));
(u1, u1)-> u1 是表示当有两个key相同的时候,取第一个,一般id是不会重复,不过难免以后会有以其他作为key的情况出现
接着遍历id列表去一个一个拿需要的数据:
for (Integer id : ids) {
User user = userMap.get(id);
/*
* 这里写业务
* */
}
这样就可以大大的减少数据库的访问了,我这里传进来的id列只有4个,那么用stream的思路就可以减少3次的访问,传进来的列表越大这样的写法性能越优,而我们写业务肯定得考虑高并发得情况,所以我觉得这个东西还是很有帮助的。
记录自己,帮助他人!