无限级数据查询
概述
在很多场景中,都有无限级查询数据的需求
数据的层级关系是不确定的,有很多层
例如一个公司有很多的部门,部门有下级部门,下级部门有下下级部门。。。
并不能确定到底有多少层
案例:
有一张课程的分类表,需要查询出所有的分类的树形结构
对应的实体类:
@Data
public class CourseType implements Serializable {
private Long id;
/**
* 类型名
*/
private String name;
/**
* 父ID
*/
private Long pid;
/**
* 子级类型
*/
private List<CourseType> children;
}
- pid就是父级类型的id,如果没有父级pid为0
- 通过children字段来存放子级类型
通过mybatis-plus来实现查询
代码递归查询
分析:
- 1 首先查询所有的顶级类型
- 2 根据顶级类型查询所有的子类型
- 3 遍历2中的子类型,继续执行第二步,递归查询直到没有
/**
* 递归查询数据库获取所有子类型树
*/
public List<CourseType> treeListByRecursion() {
// 获取顶级类型
List<CourseType> rootTypes = baseMapper
.selectList(new LambdaUpdateWrapper<CourseType>().eq(CourseType::getPid, 0));
// 递归查询获取子类型
rootTypes.forEach(item -> item.setChildren(findChildren(item)));
return rootTypes;
}
/**
* 查询当前类型的所有子类型
*/
private List<CourseType> findChildren(CourseType courseType) {
// 获取当前类型的所有子类型
List<CourseType> courseTypes = baseMapper
.selectList(new LambdaUpdateWrapper<CourseType>().eq(CourseType::getPid, courseType.getId()));
// 递归为所有子类型设置子类型
courseTypes.forEach(item -> item.setChildren(findChildren(item)));
return courseTypes;
}
mybatis递归查询
- mybatis可以通过嵌套resultMap的方式来实现查询
List<CourseType> selectTreeData();
<resultMap id="TreeResultMap" type="CourseType">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="pid" property="pid" />
<!--column="id" 把那个字段的值做了查询条件传递到另一条sql-->
<collection property="children" javaType="arrayList" ofType="CourseType"
select="cn.itsource.hrm.mapper.CourseTypeMapper.loadByPid"
column="id">
</collection>
</resultMap>
<!--resultMap="TreeResultMap" 只要有儿子就会一直查下去-->
<select id="selectByPid" parameterType="long" resultMap="TreeResultMap" >
select * from t_course_type where pid = #{pid}
</select>
<!--加载课程类型树-->
<select id="selectTreeData" resultMap="TreeResultMap">
SELECT
*
FROM t_course_type where pid = 0
</select>
- 入口是loadTreeData
- loadTreeData首先查询所有的顶级类型,返回的类型TreeResultMap
- TreeResultMap中的children字段中用了一个子查询,将当前的id传到子查询中,子查询会查询传入的id的子级类型,返回的依然是TreeResultMap,所以就会递归查询下去,直到查询完毕
代码层面处理
前面的两种方式虽然可以实现,但是需要向数据库发送很多的查询语句,会造成数据库的压力过大,可以通过代码层面来处理层级问题
- 首先查询出所有的类型
- 通过代码来实现层级的处理
public List<CourseType> treeList() {
// 1 所有的课程类型
List<CourseType> courseTypes = baseMapper.selectList(null);
// 2 课程类型的子类型
return courseTypes.stream()
// 过滤出顶级类型
.filter(courseType -> courseType.getPid() == 0)
// 查询顶级类型的子节点
.peek(courseType -> courseType.setChildren(findChildren(courseType, courseTypes)))
.collect(Collectors.toList());
}
/**
* 递归获取子类型
*/
private List<CourseType> findChildren(CourseType courseType, List<CourseType> courseTypes) {
return courseTypes.stream()
.filter(item -> item.getPid().equals(courseType.getId()))
.peek(item -> item.setChildren(findChildren(item, courseTypes)))
.collect(Collectors.toList());
}
- 首先查询所有的数据
- 过滤出顶级类型
- 查询顶级类型的子类型
- 子类型中继续递归查询子类型,直到没有为止
end

浙公网安备 33010602011771号