mysql 维护层级树字段 hierarchy (修改挂载的父节点使用代码维护hierarchy字段)

一 表结构

CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `parent_id` bigint(255) NOT NULL COMMENT '父节点id',
  `hierarchy` varchar(255) DEFAULT NULL COMMENT '层级关系',
  `name` varchar(255) NOT NULL COMMENT '用户名',
  `password` varchar(255) NOT NULL COMMENT '用户密码',
  `enabled` tinyint(255) NOT NULL DEFAULT '1' COMMENT '是否可用(0:停用 1:可用)',
  `phone` bigint(255) NOT NULL DEFAULT '0' COMMENT '手机号',
  `store_id` bigint(20) DEFAULT NULL COMMENT '门店id',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  `deleted` tinyint(2) NOT NULL DEFAULT '0' COMMENT '逻辑删(0:未删,1已删)',
  `user_type_enums` int(255) DEFAULT NULL COMMENT '角色(1:学员 2:教师 4:班主任)',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `un_password` (`password`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;

CREATE DEFINER=`root`@`%` TRIGGER `sys_user_hierarchy_triger` BEFORE INSERT ON `sys_user` FOR EACH ROW BEGIN

    DECLARE _hierarchy VARCHAR(255);

    IF (new.parent_id is not NULL) THEN

        SET _hierarchy = (
            SELECT hierarchy
            FROM sys_user
            WHERE id = new.parent_id
        );

        SET new.hierarchy = CONCAT(_hierarchy, new.parent_id, '/');

    ELSE

        SET new.hierarchy = '/';

    END
        IF;


END;

在这里插入图片描述
查询子节点的时候

//查询子节点需要加根节点的id 使用likeRight可以利用到索引
IPage<SysUser> page = this.sysUserService.page(new Page<>(pagingVO.getPage(), pagingVO.getLimit()), new LambdaQueryWrapper<SysUser>()
 .likeRight(StringUtils.isNotEmpty(vo.getHierarchy()), SysUser::getHierarchy, vo.getHierarchy() + vo.getId())

新增时利用触发器自动维护hierarchy层级字段
触发器为
在这里插入图片描述
触发器维护hierarchy

BEGIN

    DECLARE _hierarchy VARCHAR(255);

    IF (new.parent_id is not NULL) THEN

        SET _hierarchy = (
            SELECT hierarchy
            FROM sys_user
            WHERE id = new.parent_id
        );

        SET new.hierarchy = CONCAT(_hierarchy, new.parent_id, '/');

    ELSE

        SET new.hierarchy = '/';

    END
        IF;


END

修改是代码维护改层级hierarchy字段 自己写的模板代码生成

##定义Dao名
#set($daoName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Dao"))


    /**
     * 改变了父节点  所有子节点的层级字段需要维护
     *
     * @author $!author
     * @Date $!time.currTime()
     * @param id 节点自己
     * @param newParentId 新的父节点
     * @return java.lang.Boolean 是否成功
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateHierarchy(Long id, Long newParentId) {
        //父节点data
        $!{tableInfo.name}Entity byId = $tool.append("this.",$daoName,".selectById(id)");
        if (Objects.isNull(byId)) {
            throw new SZException("修改的数据不存在!");
        }
        //校验, 修改的父节点不能挂到自己本身
        if (byId.getId().equals(newParentId)) {
            throw new SZException("不能挂载到本身或本身的子节点!");
        }
        //查询需要维护的子节点
        List<$!{tableInfo.name}Entity> entitys = $tool.append("this.",$daoName,".selectList(new LambdaQueryWrapper<",$!{tableInfo.name},"Entity>()")
                .likeRight($!{tableInfo.name}Entity::getHierarchy, byId.getHierarchy() + byId.getId()));
        //校验 , 修改的父节点不能是自己的子节点
        List<Long> collect = entitys.stream()
                .map($!{tableInfo.name}Entity::getId)
                .collect(Collectors.toList());
        if (collect.contains(newParentId)) {
           throw new SZException("不能挂载到本身的子节点!");
        }
        //旧的父节点
        $!{tableInfo.name}Entity oldParent = $tool.append("this.",$daoName,".selectById(byId.getParentId());")
        //新的父节点
        $!{tableInfo.name}Entity newParent = $tool.append("this.",$daoName,".selectById(newParentId);")
        //0是根节点是存在的
        if (0 != newParentId) {
            if (Objects.isNull(newParent)) {
                throw new SZException("挂载的父节点不存在");
            }
        }
        //维护父节点parentId
        $!{tableInfo.name}Entity updateParent = new $!{tableInfo.name}Entity();
        updateParent.setId(byId.getId());
        updateParent.setHierarchy(byId.getHierarchy());
        updateParent.setParentId(newParentId);
        //维护节点的parentId
        $tool.append("this.",$daoName,".update(updateParent, new LambdaUpdateWrapper<",$!{tableInfo.name},"Entity>()")
                .eq($!{tableInfo.name}Entity::getId, byId.getId()));
        //根节点加入维护hierarchy
        entitys.add(updateParent);
        //维护节点的所有子节点的hierarchy
        entitys.forEach(entity -> {
            $!{tableInfo.name}Entity updataEntity = new $!{tableInfo.name}Entity();
            String olds ="";
            if (!Objects.isNull(oldParent) || byId.getParentId() == 0) {
                if (byId.getParentId() == 0) {
                    olds ="/";
                } else {
                    olds = oldParent.getHierarchy() + oldParent.getId() + "/";
                }
            }
            //旧的Hierarchy去掉父节点以上层级
            String s = null;
            if (StringUtils.startsWith(entity.getHierarchy(),olds)) {
                s = entity.getHierarchy().substring(olds.length());
            }
            //说明是根节点
            if (null == s || "/".equals(s)) {
                s = "";
            }
            //根节点没有id = 0的节点
            if (Objects.isNull(newParent)) {
                updataEntity.setHierarchy("/" + s);
            } else {
                updataEntity.setHierarchy(newParent.getHierarchy() + newParent.getId() + "/" + s);
            }
            //更新需要维护的hierarchy
            $tool.append("this.",$daoName,".update(updataEntity, new LambdaUpdateWrapper<",$!{tableInfo.name},"Entity>()")
                    .eq($!{tableInfo.name}Entity::getId, entity.getId()));
        });
        return true;
    }

    /**
     * 获取该节点的所有父节点 
     * @author $!author
     * @Date $!time.currTime()
     * @return java.util.List<java.lang.Long> 父节点集合
     **/
     List<Long> getParentIds(String hierarchy) {
        return Arrays.stream(hierarchy.split("/"))
                .filter(StringUtils::isNotBlank)
                .map(Long::parseLong)
                .collect(Collectors.toList());
    }
    
    /** 限制层级最多为10
     int hierarchyDeep = getHierarchyDeep(byId.getHierarchy());
     if (hierarchyDeep == 10) {
     return Result.error("最多挂载10层,无法继续挂载子节点");
     }
     **/
    /**
     * 根据树路径获取层级
     * @author $!author
     * @Date $!time.currTime()
     * @return 层级
     */
    private int getHierarchyDeep(String hierarchy) {
        return (int) (Arrays.stream(hierarchy.split("/"))
                .filter(StringUtils::isNotBlank).count() + 1);
    }

在sql里面获取一些层级关系


# 获取id=5的层级关系 result:/1/2/3/4/ 图一
select hierarchy from sys_user where id = 5;

# 转换获取层级 result:,1,2,3,4,  图二
select replace((select hierarchy from sys_user where id = 5), '/', ',');

# 切割首尾逗号 result:1,2,3,4  图三
SELECT trim(BOTH ',' FROM (select replace((select hierarchy from sys_user where id = 5), '/', ','))) as str;

# 利用mysql自带help_topic进行字符串转行结构  图四
SELECT DISTINCT substring_index(substring_index(a.str, ',', b.help_topic_id + 1), ',', - 1)
FROM (SELECT trim(BOTH ',' FROM (select replace((select hierarchy from sys_user where id = 5), '/', ','))) as str) a
         INNER JOIN mysql.help_topic b
                    ON b.help_topic_id < (length(a.str) - length(replace(a.str, ',', '')) + 1);

# 获取所有父节点数据 图五
select *
from sys_user
where id in (
    SELECT DISTINCT substring_index(substring_index(a.str, ',', b.help_topic_id + 1), ',', - 1)
    FROM (SELECT trim(BOTH ',' FROM (select replace((select hierarchy from sys_user where id = 5), '/', ','))) as str) a
             INNER JOIN mysql.help_topic b
                        ON b.help_topic_id < (length(a.str) - length(replace(a.str, ',', '')) + 1)
)

下面的sql 是看到做的笔记, 和维护层级树不相关(不相关的sql , GROUP_CONCAT收集结果集)

# xxx:yjx2,xxx11:yjx3,xxx3:yjx4,xxx4:yjx5,xxx5:yjx6,xxx6:yjx7
select GROUP_CONCAT(name, ':', password)
from sys_user
where name like 'xx%';

#获取ids 2,3,4,5,6,7
select GROUP_CONCAT(id) as str
from sys_user
where name like 'xx%';

# 使用获取的ids获取行
select *
from sys_user
where id in (
    SELECT DISTINCT substring_index(substring_index(a.str, ',', b.help_topic_id + 1), ',', - 1)
    FROM (select GROUP_CONCAT(id) as str from sys_user where name like 'xx%') a
             INNER JOIN mysql.help_topic b
                        ON b.help_topic_id < (length(a.str) - length(replace(a.str, ',', '')) + 1));

图一 : 获取id=5的层级关系 result:/1/2/3/4/
在这里插入图片描述
图二 : 转换获取层级 result:,1,2,3,4,
在这里插入图片描述
图三 : 切割首尾逗号 result:1,2,3,4
在这里插入图片描述
图四 : 利用mysql自带help_topic进行字符串转行结构
在这里插入图片描述
图五 : 获取所有父节点数据
在这里插入图片描述

发布了71 篇原创文章 · 获赞 3 · 访问量 8757

猜你喜欢

转载自blog.csdn.net/qq_40250122/article/details/103226219