You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Laravel中如何使用递归函数插入带parent_id的嵌套数组数据

无限层级嵌套数据递归入库实现方案

核心逻辑

无需提前预知数据嵌套层数,递归处理遵循固定规则即可:

  • 处理单个节点时,先写入当前节点数据到数据库,获取插入生成的主键ID
  • 若当前节点存在非空的children子节点数组,遍历所有子节点,将当前节点的主键ID作为子节点的parent_id,复用同一处理逻辑逐个处理子节点
  • 子节点完成入库后,会自动处理自身的下一级子节点,直到节点children为空时,当前分支递归终止

前置准备

首先确保存储表包含必要字段,以MySQL分类表为例,建表语句如下:

CREATE TABLE `fruit_category` (
  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `label` varchar(100) NOT NULL DEFAULT '' COMMENT '分类名称',
  `parent_id` int unsigned NOT NULL DEFAULT '0' COMMENT '父级ID,顶级节点值为0',
  PRIMARY KEY (`id`),
  KEY `idx_parentid` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

代码实现(PHP+PDO示例)

<?php
// 读取原始JSON数据,转为PHP数组
$rawJson = <<<JSON
{
    "items": [
        {
            "label": "Apricots",
            "children": []
        },
        {
            "label": "Blackberries",
            "children": []
        },
        {
            "label": "Blueberries",
            "children": [
                {
                    "label": "Blackcurrant",
                    "children": [
                        {
                            "label": "Blackcurrant blanc Petits Grains",
                            "children": []
                        },
                        {
                            "label": "Blackcurrant of Alexandria",
                            "children": [
                                {
                                    "label": "Normal",
                                    "children": []
                                },
                                {
                                    "label": "Hanepoot",
                                    "children": []
                                }
                            ]
                        },
                        {
                            "label": "Blackcurrant of Scanzorosciate",
                            "children": []
                        }
                    ]
                },
                {
                    "label": "Coconut Meat",
                    "children": []
                },
                {
                    "label": "Clementine",
                    "children": []
                },
                {
                    "label": "Cherries",
                    "children": []
                },
                {
                    "label": "Cranberries",
                    "children": []
                }
            ]
        },
        {
            "label": "Gooseberries",
            "children": []
        },
        {
            "label": "Honeydew Melon",
            "children": [
                {
                    "label": "Java-Plum",
                    "children": []
                },
                {
                    "label": "Lemon",
                    "children": []
                }
            ]
        }
    ]
}
JSON;
$data = json_decode($rawJson, true);

// 初始化数据库连接,替换为实际的数据库配置
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', 'root', 'your_db_password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// 定义递归处理函数
function processNode(array $node, int $parentId, PDO $pdo): void
{
    // 插入当前节点数据
    $stmt = $pdo->prepare("INSERT INTO fruit_category (label, parent_id) VALUES (?, ?)");
    $stmt->execute([$node['label'], $parentId]);
    // 获取当前节点插入后的自增ID,作为下一级子节点的parent_id
    $currentId = (int)$pdo->lastInsertId();

    // 没有子节点直接终止当前分支递归
    if (empty($node['children'])) {
        return;
    }

    // 遍历所有子节点递归处理
    foreach ($node['children'] as $childNode) {
        processNode($childNode, $currentId, $pdo);
    }
}

// 开启事务(可选,避免中途插入失败产生脏数据)
$pdo->beginTransaction();
try {
    // 从顶级节点开始遍历,顶级节点parent_id固定为0
    foreach ($data['items'] as $topNode) {
        processNode($topNode, 0, $pdo);
    }
    $pdo->commit();
    echo "所有层级数据入库完成";
} catch (Exception $e) {
    $pdo->rollBack();
    echo "入库失败,已回滚:" . $e->getMessage();
}
?>

注意事项

  • 递归深度限制:PHP默认递归深度限制为100层,常规分类场景不会触发该限制,如果存在超深层级需求,可以通过ini_set('xdebug.max_nesting_level', 1000)调整限制,也可以改用数组模拟栈的非递归实现,完全规避层数限制
  • 事务使用:数据量较大或者对数据一致性要求高的场景,必须加事务包裹全量入库逻辑,任意节点插入失败时整体回滚,避免出现孤立的无效数据
  • 字段扩展:如果节点存在其他业务字段,只需要在插入语句中补充对应的字段映射即可,递归核心逻辑不需要改动

内容的提问来源于stack exchange,提问作者Joney Spark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:45:41