实际开发中肯定会遇到需要查询节点树的情况。今天就为大家介绍几种查询节点树的方式。
表结构简单设计如下:
CREATE TABLE `market` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT ,
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT ,
`parent_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT ,
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '市场表' ROW_FORMAT = DYNAMIC;
<方式一> SQL语句的方式
xml中的节点Tree查询方法如下:
<mapper namespace="xxx.mapper对应的包路径">
<resultMap id="BaseResultMap"
type="对应实体的包路径">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="code" property="code" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="parent_code" property="parentCode" jdbcType="VARCHAR"/>
</resultMap>
<!--映射当前节点的子节点结果-->
<resultMap id="childrenNodeTreeResult"
type="xxx.xxx"
extends="BaseResultMap">
<collection property="childNode" column="code"
ofType="com.springboot.example.mysqltree.model.entity.TreeTable" javaType="java.util.ArrayList"
select="nextNodeTree">
</collection>
</resultMap>
<sql id="Base_Column_List">
id,
code,
name,
parent_code
</sql>
<!--查找下一个子节点-->
<select id="nextNodeTree" resultMap="childrenNodeTreeResult">
SELECT
<include refid="Base_Column_List"/>
FROM market
WHERE parent_code = #{code}
</select>
<select id="getNodeTree" resultMap="childrenNodeTreeResult">
SELECT
<include refid="Base_Column_List"/>
FROM market
WHERE parent_code = '0' # 此处的0代表顶级节点的code (比如全部下挂着一级分组 二级分组类似这样)
</select>
</mapper>
<方式二> 代码控制
先查询到最外层的父节点,遍历父节点,递归找到每个父节点下的子节点并封装(此方法不宜层级太多的情况,会产生性能问题)
#找到最外层父节点列表
List<Market> nodeTree = marketMapper.selectList(......参数自己写哦);
// 递归找到每个父节点下的子节点
nodeTree.forEach(this::findAllChild);
public void findAllChildNodes(Market market) {
List<Market> resources = marketMapper
.selectList(new LambdaQueryWrapper<Market>().eq(Market::getGroupId, market.getCode()));
market.setChildNode(resources);
if (!CollectionUtils.isEmpty(resources)) {
resources.forEach(this::findAllChild);
}
}
<方式三 -推荐> 在内存中做数据的组装
相比于上面两种方式,更推荐使用此方式。减少数据库资源浪费的同时,提升了性能。
如图所示,思路很简单,我们以顶级节点一1为例子(如果有多个顶级节点也是同样的道理)。 先找出顶级节点1下的所有子节点(不包含自己),实际我们是拿出了数据库每一行的记录。然后根据父节点分组得到一个Map<key,value>, key = 父节点id, value= 父节点为key的子节点结合。 然后遍历每一行的记录,将每个节点下的子节点挂靠上,就结束了。
`// 获取当前根节点下的所有子节点 List allChildrenNodeList = nodeRepository.list(new QueryWrapper().lambda() .eq(Node::getRootId, node.getId()) .ne(CommonEntity::getId, node.getId()));
if (CollectionUtils.isEmpty(allChildrenNodeList)) {
return;
}
Map<String, List<Node>> parentGroupList = allChildrenNodeList.stream()
.filter(node ->
node.getParentId() != null)
.collect(Collectors.groupingBy(Node::getParentCode));
// 先挂靠父节点是根节点分组
node.setChildren(parentGroupList.get(node.getId()));
allChildrenNodeList.forEach(b ->
b.setChildren(parentGroupList.get(b.getId())));`