多对多关系(如 课程-课时、用户-角色)通过中间表维护。更新时面临「如何同步前端提交的 ID 列表与数据库现状」的问题。本文对比「全量删除重建」与「增量差异同步」两种方案,给出代码实现与选型建议。
classes(课程)lessons(课时)lesson_classes (class_id, lesson_id)$lesson_ids = [1, 3, 5, 7](新关联列表)classes->classEdit($id, $data); // 更新主表
if ($res) {
// 1. 删除所有旧关联
$bool = $this->lesson_classes->lessonClassesDel($id);
if ($bool) {
// 2. 循环插入新关联
foreach ($lesson_ids as $val) {
$arr = ['class_id' => $id, 'lesson_id' => $val];
$this->lesson_classes->lessonClassesAdd($arr);
}
}
$this->show_tips('操作成功!');
} else {
$this->show_tips('操作失败!');
}
?>
弊端:并发下「删了没加上」导致数据丢失;大批量删除触发锁升级、主从延迟、外键级联风险;无法审计变更历史。
lesson_classes->getByClassId($id); // 返回 [['lesson_id'=>1], ['lesson_id'=>2]...]
$arr_old = array_column($old_rows, 'lesson_id'); // [1, 2]
// 2. 计算差异集
$arr_new = $lesson_ids; // [1, 3, 5, 7]
$intersect = array_intersect($arr_old, $arr_new); // 交集:[1] 保留不动
$result_del = array_diff($arr_old, $intersect); // 旧有新无:[2] 删除
$result_add = array_diff($arr_new, $intersect); // 新有旧无:[3,5,7] 新增
// 3. 执行新增
$bool_add = true;
if ($result_add) {
foreach ($result_add as $val) {
$bool_add &= $this->lesson_classes->lessonClassesAdd(['class_id' => $id, 'lesson_id' => $val]);
}
}
// 4. 执行删除
$bool_del = true;
if ($result_del) {
foreach ($result_del as $val) {
$bool_del &= $this->lesson_classes->lessonClassesDel($id, $val);
}
}
if ($bool_add && $bool_del) {
$this->show_tips('操作成功!');
} else {
$this->show_tips('操作失败!');
}
?>
| 维度 | 全量重建 | 增量差异 |
|---|---|---|
| 代码复杂度 | 低 | 中 |
| 数据安全性 | 低(删除窗口期风险) | 高(仅操作变更行) |
| 并发性能 | 差(全表锁/大量行锁) | 优(精准行锁) |
| 审计/日志 | 难(全删全增) | 易(明确增删记录) |
| 适用场景 | 数据量极小、低并发、无审计需求 | 通用生产环境、高并发、需审计 |
beginTransaction();
try {
// 增删操作...
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
?>
增量差异同步是中间表更新的标准模式,配合事务与乐观锁,可构建健壮的多对多关系管理模块。