如何校验多对多表中两个复合索引字段的组合是否已存在?
多对多中间表联合唯一索引重复校验方案
你当前使用的是Laravel框架的多对多关联,中间表已设置question_id + query_id联合唯一索引,可通过以下几种方案实现重复校验:
方案1:插入前主动校验
适合需要明确告知用户某条数据重复、需单独处理重复逻辑的场景,在attach前先判断关联是否存在:
for ($i = 0; $i < $len; $i++) { $questionId = $questions[$i]->id; // 校验当前question_id是否已经和当前query绑定 $exists = $query->getQuestions()->where('id', $questionId)->exists(); if (!$exists) { $query->getQuestions()->attach($questionId, [ 'score' => $scores[$i], 'answer' => $answers[$i], 'sub_test_id' => $section->id, 'test_id' => $section->getTest->id ]); } }
方案2:使用syncWithoutDetaching批量处理(推荐)
Laravel关联提供的syncWithoutDetaching方法天生支持跳过已存在的关联,不会触发重复报错,还支持批量操作减少数据库IO,性能远高于循环attach:
$syncData = []; for ($i = 0; $i < $len; $i++) { $syncData[$questions[$i]->id] = [ 'score' => $scores[$i], 'answer' => $answers[$i], 'sub_test_id' => $section->id, 'test_id' => $section->getTest->id ]; } // 已存在的关联不会重复插入,默认保留原有枢轴字段值 $query->getQuestions()->syncWithoutDetaching($syncData);
如果需要重复时覆盖更新最新的score、answer等字段,可以调用$query->getQuestions()->sync($syncData, false)即可
方案3:数据库唯一索引兜底(并发场景必备)
就算代码做了前置校验,高并发场景下依然可能出现「校验通过后、插入完成前有其他请求插入了相同数据」的情况,此时可以捕获数据库抛出的唯一约束异常做兜底处理:
use Illuminate\Database\UniqueConstraintViolationException; try { // 你的插入逻辑,attach或者sync都可以 } catch (UniqueConstraintViolationException $e) { // 重复插入的处理逻辑 }
内容的提问来源于stack exchange,提问作者Majestic99
相关产品推荐
相关产品推荐

