无限级数据查询

概述

在很多场景中,都有无限级查询数据的需求

数据的层级关系是不确定的,有很多层

例如一个公司有很多的部门,部门有下级部门,下级部门有下下级部门。。。
并不能确定到底有多少层

案例:

有一张课程的分类表,需要查询出所有的分类的树形结构

对应的实体类:

@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

posted @ 2022-04-08 19:08  茶音白  阅读(222)  评论(0)    收藏  举报