插入Laravel行重复,带有带有种族条件的updateOrCreate方法



我的控制器中有创建预测的功能:

public function updateOrCreate(Request $request, $subdomain, $uuid)
{
$fixture = Fixture::where('uuid',$uuid)->firstOrFail();
request()->validate([
'local_team_score' => 'integer|min:0',
'visitor_team_score' => 'integer|min:0',
'winner_team_id' => 'integer|nullable'
]);
if ($fixture->status !== "PENDING"){
return response()->json([
'message' => "You can not add or modify a forecast if the fixture is not pending"
], 403);
}
$winner_team = null;
// local team win
if ($request->local_team_score > $request->visitor_team_score) {
$winner_team = $fixture->localTeam;
}elseif ($request->local_team_score < $request->visitor_team_score){ //visitor win
$winner_team = $fixture->visitorTeam;
}else{ // draw
$winner_team = FixtureTeam::where('team_id',$request->winner_team_id)->first();
}
$user = auth('api')->user();
$platform = Platform::first();
$forecast = Forecast::updateOrCreate([
'user_id' => $user->id,
'fixture_id' => $fixture->id,
'platform_id' => $platform->id
],[
'local_team_score' => $request->local_team_score,
'visitor_team_score' => $request->visitor_team_score,
'winner_team_id' => is_null($winner_team) ? null : $winner_team->team_id
]);
$forecast->load('winnerTeam');
return new ForecastResource($forecast);
}

正如您所看到的,我使用updateOrCreate方法来添加或更新预测。

问题是,当来自同一用户的两个请求同时运行(并且尚未创建预测(时,插入了2行。

你有解决方案吗?我知道这个问题并不新鲜,但我找不到解决办法https://github.com/laravel/framework/issues/19372

updateOrCreate执行两个步骤:

  1. 尝试获取记录
  2. 根据结果进行更新或创建
    此操作不是原子操作,这意味着在第1步和第2步之间,另一个进程可能会创建该记录,但最终会出现重复(您的情况(

要解决您的问题,您需要以下内容:

  1. 确定哪些列将赋予记录的唯一性,并添加唯一索引(可能是user_id、fixture_id和platform_id之间的复合索引(
  2. 您需要让数据库处理upstart(MySQL中的ON DUPLICATE KEY UPDATE,Postgres中的ON CONFLICT (...) DO UPDATE SET,等等(。这可以在Laravel中通过使用upsert(array $values, $uniqueBy, $update = null)而不是updateOrCreate来实现

最新更新