一、前言
在开发的时候为了图方便和结构清晰,我们有时会在项目中使用@Many注解来实行实体类内部一对多的数据获取,如
@Select("...")
@Results({
@Result(property = "XXXX", javaType = List.class, many = @Many(select = "XXXX",
fetchType = FetchType.EAGER), column = "XXXX")
})
List<EntityA> getXXXXEntities(QueryParam param);
这种写法在数据量增加至千,万级别时,响应时间会明显增长(很容易就能达到十几秒以上),这很明显不能直接应用到生产中,分析:
发起查询时,先查出@select的结果封装成实体类对象,再根据加载策略(fetchType = FetchType.EAGER,这里是即时加载),针对查到的每个实体类对象去加载其内部的List类型的一对多的值,这样针对每个实体类对象都需要额外的对数据库重新发起一次查询请求,这样一来速度自然就会下降。
二、解决办法
减少向数据库发起的请求次数
一(A)对多(B)查询时,先查出符合条件的List<A> aList 集合,抽取其中的关键字集合去查符合条件的List<B> bList 集合,再将blist按关键字进行分组,遍历aList进行填充 (使用 bList.stream().collect(Collectors.groupingBy(b -> b.get关键字(), LinkedHashMap::new, Collectors.toList()) )
另外,如果“多”的那个实体属性很少,可以使用SQL一次性查出来,在setter中进行装配。
一对多(实体类 对 String)
//实体类
public class Department{
...
List<String> employees; //员工姓名
public void setEmployeesAll(String employeeAll){
employees = employeeAll.split("@");
}
}
@Select("select dep.x1,dep.x2...,dep.x3," +
"(select GROUP_CONCAT(employee.name ORDER BYemployee.name ASC SEPARATOR '@')\n" +
"from employee \n" +
"where employee.department_id = department.department_id \n" +
"GROUP BY employee.department_id LIMIT 1) " +
"as employeeAll from department")
List<Department> getDepartments();
最后
如果你有更好的思路或者方法,欢迎指教。