
本文介绍如何将形如“Category SubCategory SubSubCategory”的反斜杠分隔字符串,逐级插入数据库并自动建立父子关系(parent_id 指向上一级新插入记录的自增 ID)。核心在于利用 PDO 的 lastInsertId() 动态获取刚插入记录的 ID 并作为下一级的 parent_id。
本文介绍如何将形如“category subcategory subsubcategory”的反斜杠分隔字符串,逐级插入数据库并自动建立父子关系(parent_id 指向上一级新插入记录的自增 id)。核心在于利用 pdo 的 `lastinsertid()` 动态获取刚插入记录的 id 并作为下一级的 parent_id。
在构建多级分类系统时,常需将层级路径字符串(如 "A B C")解析为树状结构并持久化到数据库。关键挑战在于:每插入一个分类,其 parent_id 必须指向其直接上级分类刚生成的主键 ID,而非固定值 0。
以下为安全、高效且符合数据库最佳实践的实现方案:
✅ 正确做法:预处理 + 参数化查询 + 动态 parent_id
$cats = "Category \ SubCategory \ SubSubCategory"; // 注意:PHP 中反斜杠需转义为 "\"
$categories = array_map('trim', explode('\', $cats)); // 自动去除首尾空格
// 使用预编译语句防止 SQL 注入
$stmt = $db->prepare("INSERT INTO cat (name, parent_id) VALUES (:name, :parent)");
$stmt->bindParam(':name', $category, PDO::PARAM_STR);
$stmt->bindParam(':parent', $parent, PDO::PARAM_INT);
$parent = 0; // 根分类 parent_id = 0
foreach ($categories as $category) {
if (empty($category)) continue; // 跳过空项(防意外空格或重复分隔符)
$stmt->execute();
$parent = $db->lastInsertId(); // 获取本次插入生成的 id,作为下一级的 parent_id
}
⚠️ 重要注意事项
- 反斜杠转义:PHP 字符串中 是转义字符,原始数据若来自表单或文件,应确保传入的是字面量反斜杠(即 "A \ B" 或使用单引号 'A B'),否则 explode('\', ...) 将失效。
- SQL 注入防护:绝对避免字符串拼接 SQL(如原代码中的 "INSERT ... '" . $category . "'"),必须使用参数化查询(prepare/execute)。
- 空值与空白处理:array_map('trim', ...) 和 empty() 检查可防御因多余空格或空段导致的无效记录。
-
事务保障(推荐):对于完整路径的插入,建议包裹在事务中,确保全部成功或全部回滚:
$db->beginTransaction(); try { // 上述 foreach 循环... $db->commit(); } catch (Exception $e) { $db->rollback(); throw $e; }
? 最终效果(对应示例数据)
| id | name | parent_id |
|---|---|---|
| 1 | Category | 0 |
| 2 | SubCategory | 1 |
| 3 | SubSubCategory | 2 |
该方案清晰体现了层级依赖关系,且具备健壮性、安全性与可维护性,适用于 CMS、电商类目、文档目录等典型场景。










