分类表返回树形结构

前言

多级分类在实战应用场景会出现很多,就比如你登录某个京东平台,你就会看到有商品分类。

红色方框内的都是各级分类的名称,所以分类在一个项目中是很有必要存在的,它可以提高用户的使用体验。所以怎么设计多级分类表就是一个关键因素了,我当时第一次接触这个多级分类的时候,我脑海的第一个想法是建表建无数个表,但是我少考虑的因素就是,这个创建分类是前端的事,前端难道创建一个分类就去创建一个表吗,这不可能的事所以要把分类抽象的看成一个字段就行了,创建分类目录,就相当于添加一条记录。

正文

有了这种思路,我们就可以创建一个最简单的分类表了。我把它命名为递归查询分类表。

实际上我只是不知道他叫什么名字,所以才这样取名字的。

先说一下,递归查询分类表有什么优缺点吧。

优点:就是他太过于普通普通到可以适用于任何数据库。

缺点:因为用到递归这个算法,所以当分类无限的分配下去,也就是说它的根部无限的远的情况下,各种性能问题也就伴随而来。

递归查询分类表如何建表

id

分类名称

父级id

分类等级

分类内容

1

一级文件夹

0

1

2

二级文件夹(手机)

1

2

手机配件

3

二级文件夹(手机)

1

2

手机通讯

4

三级文件夹(手机通讯)

3

3

游戏手机

5

三级文件夹(手机通讯)

3

3

二手手机

根据上面京东的页面我可以建立出这样的表。

画一个该表的原型大概如下

这样就是一个简单的分类表了,但是分类表建立起来是容易使用起来就需要一定的方式,就像开篇就说了,这种分类表的建立查询所有分类的时候就需要用到递归的方式来获取,如果根部很深,那么你的查询就会超时,就会报错,然后数据库就会崩掉,但是话又说回来了,如果分类等级可以确定在三级内,这种方式反而更方便,因为他的逻辑没有太大的难度。

下面我会给出递归查询返回树形结构的核心代码:

 @Override

    public List<Category> findAllCategories() {

        // 1. 查询所有分类

        List<Category> allCategories = (List<Category>) categoryRepository.findAll();



        // 2. 创建两个Map,一个用于存储分类ID到分类对象的映射,另一个用于存储父分类ID到子分类列表的映射

        Map<Integer, Category> categoriesById = new HashMap<>();

        Map<Integer, List<Category>> childrenByParentId = new HashMap<>();



        // 3. 遍历所有分类,填充两个Map

        for (Category category : allCategories) {

            categoriesById.put(category.getId(), category); // 存储分类ID到分类对象的映射

            if (!childrenByParentId.containsKey(category.getParentId())) {

                childrenByParentId.put(category.getParentId(), new ArrayList<>()); // 如果父分类ID对应的子分类列表不存在,则创建一个新的列表

            }

            childrenByParentId.get(category.getParentId()).add(category); // 将当前分类添加到其父分类的子分类列表中

        }



        // 4. 获取所有根分类(父ID为0的分类)

        List<Category> rootCategories = new ArrayList<>(childrenByParentId.get(0));



        // 5. 调用递归方法构建树形结构

        buildTree(rootCategories, childrenByParentId);



        // 6. 返回根分类列表

        return rootCategories;

    }



    /**

     * 递归构建树形结构。

     *

     * @param categories 当前层级的分类列表

     * @param childrenByParentId 父分类ID到子分类列表的映射

     */

    private void buildTree(List<Category> categories, Map<Integer, List<Category>> childrenByParentId) {

        for (Category category : categories) {

            // 获取当前分类的所有子分类

            List<Category> children = childrenByParentId.get(category.getId());

            if (children != null) {

                category.setChildren(children); // 设置当前分类的子分类列表

                buildTree(children, childrenByParentId); // 递归调用,继续构建子分类的子分类

            }

        }

    }

}

返回的格式

[

  {

    "id": 1,

    "name": "电子产品",

    "children": [

      {

        "id": 3,

        "name": "智能手机",

        "children": []

      },

      {

        "id": 4,

        "name": "笔记本电脑",

        "children": [

          {

            "id": 6,

            "name": "游戏本",

            "children": []

          },

          {

            "id": 7,

            "name": "轻薄本",

            "children": [

              {

                "id": 8,

                "name": "超轻薄本",

                "children": []

              }

            ]

          }

        ]

      },

      {

        "id": 5,

        "name": "智能穿戴设备",

        "children": []

      }

    ]

  },

  {

    "id": 2,

    "name": "服装",

    "children": []

  }

]

这就是递归分类表,当然除了递归分类表还有其他的方式来建表,

比如:

路径记录法:

优点就是:查询速度快。

缺点:更新时需要更新所有子节点的路劲信息。

   CREATE TABLE categories (

       id INT AUTO_INCREMENT PRIMARY KEY,

       name VARCHAR(255) NOT NULL,

       parent_id INT DEFAULT 0,

       path VARCHAR(255),

       description TEXT,

       sort_order INT DEFAULT 0,

       FOREIGN KEY (parent_id) REFERENCES categories(id)

   );

   

嵌套集模型

使用两个字段来表示分类的位置,如left_value和right_value。

优点:是查询速度快。

缺点:是插入和删除操作较为复杂。   

   CREATE TABLE categories (

       id INT AUTO_INCREMENT PRIMARY KEY,

       name VARCHAR(255) NOT NULL,

       parent_id INT DEFAULT 0,

       path VARCHAR(255),

       description TEXT,

       sort_order INT DEFAULT 0,

       FOREIGN KEY (parent_id) REFERENCES categories(id)

   );

闭包表法:

使用额外一张表来记录父子关系,适合于复杂的多级关系。

优点:是查询速度。

缺点:是需要额外的存储空间

   CREATE TABLE category_closure (

       id INT AUTO_INCREMENT PRIMARY KEY,

       parent_id INT NOT NULL,

       child_id INT NOT NULL,

       FOREIGN KEY (parent_id) REFERENCES categories(id),

       FOREIGN KEY (child_id) REFERENCES categories(id)

   );

缓存机制:对于频繁访问的分类数据,可以使用缓存来提高性能。

索引优化:为parent_id、left_value和right_value等字段创建索引。

后面我会分享其他分类表如何快速获取树形结果。感兴趣的小伙伴可以持续关注一下。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现 MySQL 多树形结构递归可以使用递归查询和连接查询,下面是一个简单的示例: 假设有两个,一个是分类 `category`,另一个是分类关系 `category_relationship`,其中 `category` 包含分类的基本信息,`category_relationship` 包含分类之间的层次关系。 category 结构: ``` id INT PRIMARY KEY, name VARCHAR(50) NOT NULL ``` category_relationship 结构: ``` id INT PRIMARY KEY, parent_id INT NOT NULL, child_id INT NOT NULL ``` 其中,`parent_id` 示父分类的 id,`child_id` 示子分类的 id。 现在,我们要查询分类之间的树形结构,可以使用以下 SQL 语句: ``` WITH RECURSIVE category_tree(id, name, parent_id, level) AS ( SELECT id, name, NULL, 0 FROM category WHERE id = 1 -- 根节点的 id UNION ALL SELECT c.id, c.name, cr.parent_id, ct.level + 1 FROM category c JOIN category_relationship cr ON c.id = cr.child_id JOIN category_tree ct ON cr.parent_id = ct.id ) SELECT id, name, parent_id, level FROM category_tree; ``` 上述 SQL 语句中,使用了 WITH RECURSIVE 关键字来定义递归查询。首先查询根节点,然后通过连接查询和递归查询,找到所有与根节点相关的子节点,并按照层次关系进行排序。 最终,返回的结果集中包含每个分类节点的 id、name、parent_id 和 level。其中,id 分类节点的唯一标识符,name 分类节点的名称,parent_id 分类节点的父节点 id,level 分类节点在树形结构中的层次。 需要注意的是,以上示例仅供参考,实际应用中还需要根据具体情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值