TP5.1 怎么实现多级分销?闭包表与路径枚举算法实战【递归】

酷静君_4155

酷静君_4155

2026-07-07

228人浏览

原创

闭包表通过预存所有祖先-后代关系实现o(1)查询,建表需复合主键(ancestor,descendant)和descendant索引,插入时必须包含depth=0自环及完整层级路径;path字段更新须封装显式方法并重算整链,tp5.1递归查询需限深防循环;佣金结算优先闭包表,低频查询可用path;两者需与用户状态变更强耦合。

tp5.1 怎么实现多级分销?闭包表与路径枚举算法实战【递归】

闭包表怎么建,为什么比 parent_id 递归快

直接用 parent_id 查三级下线,每次都要 JOIN 多次 users 表,1000 个用户就得发 3000 条 SQL;而闭包表把所有祖先-后代关系提前存好,查某人全部上级只要一条 SQL:SELECT ancestor FROM relation_closure WHERE descendant = ?。

建表语句必须带复合主键和索引:

CREATE TABLE relation_closure (
  ancestor INT NOT NULL,
  descendant INT NOT NULL,
  depth INT NOT NULL,
  PRIMARY KEY (ancestor, descendant),
  INDEX idx_descendant (descendant)
);
  • depth = 0 表示自己到自己,插入新用户时必须先写这一行
  • 用户 A 邀请 B,B 邀请 C,则要插入:(A,A,0)、(B,B,0)、(C,C,0)、(A,B,1)、(A,C,2)、(B,C,1)
  • 千万别漏掉 depth 字段——它能直接区分一级、二级,避免 PHP 侧再算层级

路径枚举(path 字段)怎么更新才不丢数据

用 path 字段(如 "0-100-205")实现快速 LIKE 查询,但更新逻辑极易出错:模型事件里改 path 会因事务回滚或并发写丢失;手动在注册后立即更新又容易漏掉升级、迁移等场景。

正确做法是封装成独立方法,在业务关键点显式调用:

ThinkPHP5.1企业站点快速开发-源码课件
ThinkPHP5.1企业站点快速开发-源码课件

ThinkPHP5.1企业站点快速开发

下载
  • 用户注册成功后,立刻执行:$user->path = $parent ? $parent->path . '-' . $parent->id : '0';
  • 用户更换上级(如冻结原上级后指定新推荐人),必须重算整条链路:rebuildPath($user->id),不能只改当前行
  • path 字段开头固定为 0,否则 WHERE path LIKE '0-100-%' 会匹配失败
  • 字段长度至少设为 VARCHAR(255),5 级以上分销很容易超长

TP5.1 里怎么写一个安全的递归查询函数

ThinkPHP 5.1 自带的 with() 不适合多级分销——它默认 N+1,查 100 个下线就发起 100 次 SQL;手写递归函数又容易栈溢出或无限循环。真正稳的做法是限制深度 + 提前终止。

下面这个函数控制最多查 3 层,且自动防循环引用:

protected function getDownlines($userId, $maxLevel = 3, $currentLevel = 1, $visited = []) {
    if ($currentLevel > $maxLevel || in_array($userId, $visited)) {
        return [];
    }
    $children = Db::name('users')->where('pid', $userId)->select();
    $result = [];
    foreach ($children as $child) {
        $result[] = [
            'id' => $child['id'],
            'level' => $currentLevel,
            'children' => $this->getDownlines($child['id'], $maxLevel, $currentLevel + 1, array_merge($visited, [$userId]))
        ];
    }
    return $result;
}
  • 必须传入 $visited 数组,否则父子互绑(A 的 pid 是 B,B 的 pid 又设成 A)会导致死循环
  • 别在控制器里直接调这个函数——佣金结算、报表导出等场景要用它,应抽成服务类方法
  • 返回结构带 level 字段,前端或后续计算可直接用,不用再解析 path

佣金结算该用闭包表还是 path 字段

高频结算(比如每笔订单完成都要算)必须用闭包表;低频查询(比如后台看某个用户的下级列表)用 path 更省事。两者不是二选一,而是分工明确。

  • 结算时走闭包表:SELECT u.id, u.level, rc.depth FROM users u JOIN relation_closure rc ON u.id = rc.ancestor WHERE rc.descendant = ? AND rc.depth BETWEEN 1 AND 3
  • 查“某人所有二级下线”这种简单需求,path 一行搞定:WHERE path LIKE '0-100-%' AND LENGTH(path) - LENGTH(REPLACE(path, '-', '')) = 3(注意减 1 才是相对级数)
  • 闭包表插入成本高,但查得快;path 插入快,但修改上级时要批量更新子树——如果业务中换上级频繁,闭包表更稳

真正容易被忽略的是:无论选哪种方案,佣金计算逻辑必须和用户状态强耦合——上级被冻结、降级、注销,都要触发重算,不能只依赖静态路径或关系表快照。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

thinkphp

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

2025.07.29

4173

19

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

2023.08.14

5716

4

Python uv使用教程
Python uv使用教程

本专题汇总了 Python uv 使用教程与高效使用指南,从 uv 安装配置、常用命令到虚拟环境、依赖管理与项目打包,系统讲解如何用 uv 替代 pip 与 poetry,全面提升 Python 项目开发效率,助你快速上手这一现代化包管理工具,打造干净高效的 Python 工作流。

2026.10.15

0

15

剧云AI短剧创作教程合集
剧云AI短剧创作教程合集

本专题聚焦剧云AI短剧创作,讲解从短剧灵感、梗概、全局大纲到分集、分场和正文的完整流程及节奏设计方法。

2026.10.14

0

15

剧云AI剧本创作零基础入门
剧云AI剧本创作零基础入门

本专题系统讲解剧云AI剧本创作流程,涵盖灵感、梗概、大纲、分场与正文生成,帮助新手快速完成首个中文剧本项目。

2026.10.14

0

14

VibeKnow文档转视频操作指南
VibeKnow文档转视频操作指南

本专题讲解VibeKnow上传Word、TXT、Markdown等材料生成视频的方法,覆盖内容解析、脚本组织、画面生成与成片检查。

2026.10.14

0

15

VibeKnow知识视频制作与导出详解
VibeKnow知识视频制作与导出详解

本专题整理VibeKnow从注册、素材上传、AI生成到预览导出的完整操作,帮助新手快速制作第一条知识讲解视频。

2026.10.14

0

13

二狗PPT大纲编辑实操指南
二狗PPT大纲编辑实操指南

本专题聚焦二狗PPT结构化大纲的生成和修改,讲解标题、正文、目录、页数与页面顺序的调整方法,提升汇报逻辑和内容完整性。

2026.10.14

0

15

二狗PPT文档转PPT全教程
二狗PPT文档转PPT全教程

本专题讲解二狗PPT解析Word、PDF、Excel和PPT资料的方法,涵盖文件上传、内容提取、大纲整理、异常处理与转换后校对。

2026.10.14

0

13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程