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

求助:将Mysqli删除父类及子类代码转为PDO时遇问题

嘿,我来帮你把这段删除父类及子类的MySQLi代码转换成PDO实现,同时梳理清楚关键细节,避免踩坑~

首先先补全你提到的那段可正常运行的MySQLi示例代码(根据常见逻辑补全):

// Delete
if(isset($_GET['delete']) && !empty($_GET['delete'])) {
    $delete_id = (int)$_GET['delete'];
    $delete_id = sanitize($delete_id);

    /* Deleting a parent and its children */
    // 查询所有一级子类ID
    $get_children = $db->query("SELECT id FROM categories WHERE parent = '$delete_id'");
    // 循环删除子类
    while($child = mysqli_fetch_assoc($get_children)){
        $db->query("DELETE FROM categories WHERE id = '{$child['id']}'");
    }
    // 删除父类
    $db->query("DELETE FROM categories WHERE id = '$delete_id'");

    header('Location: categories.php');
    exit();
}
转换后的PDO实现方案

首先确保你已经正确建立了PDO连接(示例连接代码如下,记得替换成你的数据库信息):

$pdo = new PDO(
    "mysql:host=localhost;dbname=your_database;charset=utf8mb4",
    "your_username",
    "your_password",
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 开启异常模式,方便错误处理
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // 默认关联数组返回
    ]
);

然后是核心的删除逻辑:

// 处理删除请求
if (isset($_GET['delete']) && !empty($_GET['delete'])) {
    $delete_id = (int)$_GET['delete'];
    // 这里的sanitize针对整数来说,(int)强制转换已经足够安全,PDO预处理会进一步加固

    try {
        // 开启事务!保证删除操作原子性:要么父类+子类全删,要么全不删,避免孤儿数据
        $pdo->beginTransaction();

        // 方案1:仅删除一级子类(对应原MySQLi逻辑)
        // 先删子类
        $deleteChildren = $pdo->prepare("DELETE FROM categories WHERE parent = :delete_id");
        $deleteChildren->bindParam(':delete_id', $delete_id, PDO::PARAM_INT);
        $deleteChildren->execute();

        // 再删父类
        $deleteParent = $pdo->prepare("DELETE FROM categories WHERE id = :delete_id");
        $deleteParent->bindParam(':delete_id', $delete_id, PDO::PARAM_INT);
        $deleteParent->execute();

        // --------------------------
        // 方案2:删除所有层级的子类(多级树形结构适用)
        // 用MySQL递归CTE一次性删除父类+所有子/孙类,效率更高
        // $deleteAll = $pdo->prepare("
        //     WITH RECURSIVE category_tree AS (
        //         SELECT id FROM categories WHERE id = :delete_id
        //         UNION ALL
        //         SELECT c.id FROM categories c
        //         JOIN category_tree ct ON c.parent = ct.id
        //     )
        //     DELETE FROM categories WHERE id IN (SELECT id FROM category_tree)
        // ");
        // $deleteAll->bindParam(':delete_id', $delete_id, PDO::PARAM_INT);
        // $deleteAll->execute();
        // --------------------------

        // 提交事务
        $pdo->commit();

        // 跳转回分类列表页
        header('Location: categories.php');
        exit();
    } catch (PDOException $e) {
        // 出错就回滚所有操作
        $pdo->rollBack();
        // 开发环境可以输出错误,生产环境建议写日志不要直接暴露
        die("删除操作失败:" . $e->getMessage());
    }
}

几个关键细节说明

  • 事务处理:这是原MySQLi代码里缺失的重要环节!如果删除子类时出错,原代码会导致父类被删除但子类残留,用beginTransaction()+commit()+rollBack()可以彻底避免这种情况。
  • 预处理语句:PDO的prepare()和bindParam()从根源上防止SQL注入,比MySQLi直接拼接SQL安全得多,指定PDO::PARAM_INT还能明确参数类型,进一步降低风险。
  • 多级子类支持:如果你的分类是多级树形(比如子类还有子类),直接用递归CTE的方案更高效,不用循环查询,一次SQL就能搞定所有关联记录的删除。
  • 错误处理:PDO的异常模式能帮你快速定位问题,生产环境记得把错误信息写入日志,不要直接输出给用户。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:12:06