当前位置 博文首页 > 废物大师兄:树形结构的菜单表设计与查询
开发中经常会遇到树形结构的场景,比如:导航菜单、组织机构等等,但凡是有这种父子层级结构的都是如此,一级类目、二级类目、三级类目。。。
对于这种树形结构的表要如何设计呢?接下来一起探讨一下
首先,想一个问题,用非关系型数据库存储可不可以?
答案是肯定可以的,比如用mongoDB,直接将整棵树存成json。但是,这样不利于按条件查询,当然也取决于具体的需求,抛开需求谈设计都是耍流氓。
在菜单这个场景下,一般还是用关系型数据库存储,可以将最终的查询结构缓存起来。
常用的方法有四种:
第一种:每条记录存储parent_id
这种方式简单明了,但是想要查询某个节点的所有父级和子级的时候比较困难,势必需要用到递归,在mysql里面就得写存储过程,太麻烦了。
当然,如果只有两级的话就比较简单了,自连接就搞定了,例如:
第四种:单独用一种表保存节点之间的关系
CREATE TABLE `city` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(16), PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4; CREATE TABLE `city_tree_path_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `city_id` int(11) NOT NULL, `ancestor_id` int(11) NOT NULL COMMENT '祖先ID', `level` tinyint(4) NOT NULL COMMENT '层级', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4;
上面这个例子中,city表代表城市,city_tree_path_info代表城市之间的层级关系,ancestor_id表示父级和祖父级ID,level是当前记录相对于ancestor_id而言的层级。这样就把整个层级关系保存到这张表中了,以后想查询某个节点的所有父级和子级就很容易了。
最后,我发现构造这种层级树最简单的还是用java代码
java递归生成菜单树
Menu.java
1 package com.example.demo.model;
2
3 import lombok.AllArgsConstructor;
4 import lombok.Data;
5 import lombok.NoArgsConstructor;
6
7 import java.util.List;
8
9 @AllArgsConstructor
10 @NoArgsConstructor
11 @Data
12 public class Menu {
13
14 /**
15 * 菜单ID
16 */
17 private Integer id;
18
19 /**
20 * 父级菜单ID
21 */
22 private Integer pid;
23
24 /**
25 * 菜单名称
26 */
27 private String name;
28
29 /**
30 * 菜单编码
31 */
32 private String code;
33
34 /**
35 * 菜单URL
36 */
37 private String url;
38
39 /**
40 * 菜单图标
41 */
42 private String icon;
43
44 /**
45 * 排序号
46 */
47 private int sort;
48
49 /**
50 * 子级菜单
51 */
52 private List<Menu> children;
53
54 public Menu(Integer id, Integer pid, String name, String code, String url, String icon, int sort) {
55 this.id = id;
56 this.pid = pid;
57 this.name = name;
58 this.code = code;
59 this.url = url;
60 this.icon = icon;
61 this.sort = sort;
62 }
63
64 }
Test.java
1 package com.example.demo.model;
2
3 import com.fasterxml.jackson.core.JsonProcessingException;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5
6 import java.util.ArrayList;
7 import java.util.Comparator;
8 import java.util.List;
9 import java.util.stream.Collectors;
10
11 public class Hello {
12 public static void main(String[] args) throws JsonProcessingException {
13 List<Menu> allMenuList = new ArrayList<>();
14 allMenuList.add(new Menu(1, 0, "湖北", "HuBei", "/a", "a", 3));
15 allMenuList.add(new Menu(2, 0, "河南", "HeNan", "/b", "b", 2));
16 allMenuList.add(new Menu(3, 1, "宜昌", "YiChang", "/c", "c", 2));
17 allMenuList.add(new Menu(4, 2, "信阳", "XinYang", "/d", "d", 1));
18 allMenuList.add(new Menu(5, 1, "随州", "SuiZhou", "/e", "e", 1));
19 allMenuList.add(new Menu(6, 5