两种常用的构建树形结构的方式
- 1:维护路径,通过路径一次将所有的节点查询出来,并制定key为节点的id,然后将所有的节点构建为一颗树
- 优点:与数据库只交互一次,构建节点的时间为O(N)
- 缺点:维护复杂,需要维护额外的路径
- 2:递归查询,直接构建为一棵树
- 优点:无脑递归插叙
- 缺点:如果在数据库中递归,关系联查询N次,如果是在代码中递归,与数据库交互查询N减最后一层节点次
表结构如下
CREATE TABLE `t_lq_tree` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`mid` int(11) NOT NULL COMMENT '我的id',
`pid` int(11) NOT NULL COMMENT '父id',
`name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '名字',
`path` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '路径',
`level` int(255) DEFAULT NULL COMMENT '层级',
PRIMARY KEY (`id`),
UNIQUE KEY `inx_mid` (`mid`),
KEY `inx_pid` (`pid`),
KEY `inx_path` (`path`)
) ENGINE=InnoDB AUTO_INCREMENT=1190 DEFAULT CHARSET=latin1;
先简单的:mybatis递归查询
1、mapper查询
@Select("select * from t_lq_tree where mid=#{mid}")
@Results({
@Result(property = "children",column = "mid",
many = @Many(select="com.lq.bootmultiple.mapper.mysqlmapper.TreeMapper.getAllNodeXByPid"))
})
NodeX getNodeXByMid(Integer mid);
@Select("select * from t_lq_tree where pid=#{mid}")
@Results({
@Result(property = "children",column = "mid",
many = @Many(select="com.lq.bootmultiple.mapper.mysqlmapper.TreeMapper.getAllNodeXByPid"))
})
List<NodeX> getAllNodeXByPid(@Param("mid") Integer mid);
2、对应的do对象
@Data
public class NodeX {
/** 主键 */
private Long id;
/** 名称 */
private String name;
/** 路径 */
private String path;
/** 等级 */
private int level;
/** 自己的id */
private Long mid;
/** 父id */
private Long pid;
/** 子集 */
private List<NodeX> children;
}
3、获取树形结构
NodeX nodeXByMid = treeMapper.getNodeXByMid(1);
维护路径的方式构建树
1、mapper
@MapKey("mid")
@Select("select * from t_lq_tree where path like " +
"concat((select path from test.t_lq_tree where mid=#{mid}),'%')")
Map<Integer,Node> getAllNodeByMid(Integer mid);
2、do对象
@Data
public class BaseTreeNode implements Serializable {
/** 自己的id */
private Long mid;
/** 父id */
private Long pid;
/** 子集 */
private List<BaseTreeNode> children;
}
@Data
public class Node extends BaseTreeNode{
/** 主键 */
private Long id;
/** 名称 */
private String name;
/** 路径 */
private String path;
/** 等级 */
private int level;
}
2、构建树形结构
/**
* 从任意节点构建一颗树
* @param nodeMap 节点集合 key是mid
* @param nodeId 当前跟节点
* @return
*/
public static <T extends BaseTreeNode> T buildTree(Map<Integer, ? extends BaseTreeNode> nodeMap, Long nodeId) {
// 树
BaseTreeNode node = new BaseTreeNode();
List<BaseTreeNode> errorNode = new ArrayList<>();
//存储脏数据
for (Map.Entry<Integer, ?> entry : nodeMap.entrySet()) {
// 获取当前节点
BaseTreeNode curNode =(BaseTreeNode) entry.getValue();
// 获取到当前节点的父节点
BaseTreeNode pNode = nodeMap.get(curNode.getPid());
// 顶级节点加入树集合
if (curNode.getMid().equals(nodeId)) {
node = (curNode);
continue;
}
// 没有父节点的脏数据,pid又不是0
if (pNode == null) {
errorNode.add(curNode);
continue;
}
if (pNode.getChildren() == null) {
pNode.setChildren(new ArrayList<>());
}
pNode.getChildren().add(curNode);
}
return (T)node;
}