在嵌套集模型中改变节点的父亲节点

472 阅读2分钟

什么是嵌套集模型

详情可以看我在掘金上的这篇文章,juejin.cn/post/684490…

大致上来说,它就是一种层级结构的模型。当对层级结构有许多的遍历操作时,使用它会十分方便。比如获取某个节点到根节点的路径,统计节点的子节点数量,或者节点及其子节点所关联的实体数量(如获取产品分类树,及其每个分类节点所拥有的产品数量)。

不过它的缺点是增加、删除、移动节点会相对而言较为复杂以及消耗性能。 尤其是移动节点,更加复杂。然而在实际应用场景当中,改变某个分类的父分类是一个比较常见的需求。下面我们就来介绍该如何实现这个需求。

如何改变节点的父亲节点

我们以如下的分类树为例子:

如果我们想让游戏节点的父节点改成音乐节点,可以按照以下步骤:

  1. 给子树创建新的空间
UPDATE category SET lft = lft + :width WHERE lft >= :newpos
UPDATE category SET rgt = rgt + :width WHERE rgt >= :newpos
  1. 把子树移动到新空间
UPDATE tags SET lft = lft + :distance, rgt = rgt + :distance
   WHERE lft >= :tmppos AND rgt < :tmppos + :width
  1. 去除被之前子树占据的空间
UPDATE category SET lft = lft - :width WHERE lft > :oldRgt
UPDATE category SET rgt = rgt - :width WHERE rgt > :oldRgt

各变量说明

int newpos = 4 + 1  // 新的父节点的lft值+1;在这里音乐节点的lft值是4
int width = node.getRgt() - node.getLft() + 1; // 原子树的宽度
int distance = newpos - node.getLft(); // 节点到新的位置的距离
int tmppos = node.getLft();

// 向后移动必须考虑新空间
if (distance < 0) {
    distance -= width;
    tmppos += width;
}

再经过上面的操作后,整个树将会变成如下:

总结

除了上面的5次sql操作,其实我们还需要查询被移动的节点以及新的父节点。所以总的来说至少需要6次sql查询。一般情况下,修改节点的父节点是一个不太频繁的操作,所以相对于它带来的好处,其实是可以接受这样的性能消耗的。