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

如何避免Laravel接口处理Flutter并发请求时重复保存相同记录

问题根因

重复写入的核心原因有两个:

  1. 逻辑漏洞:你当前的Team存在性判断只校验了user_id,没有关联week_id,就算没有并发问题,用户跨周创建队伍时也会出现逻辑错误,无法为新的活动周创建队伍。
  2. 并发竞态条件:12个异步请求几乎同时到达后端,判断Team是否存在、写入Team是两个独立的非原子操作,在第一个请求完成Team写入前,后续所有请求的存在性判断都会拿到空结果,全部进入创建分支,最终生成多条重复记录。
解决方案

1. 数据库层加唯一约束(兜底方案,必须配置)

这是最可靠的防线,就算上层逻辑出问题也不会产生脏数据。给teams表添加user_id和week_id的联合唯一索引,执行如下迁移代码:

Schema::table('teams', function (Blueprint $table) {
    $table->unique(['user_id', 'week_id']);
});

如果需要避免同个俱乐部被重复加入同一个队伍,也可以给user_teams表加team_id和club_id的联合唯一索引。

2. 代码层使用原子查询方法替代分离的判断+写入

用Laravel内置的firstOrCreate方法,该方法配合数据库唯一索引可保证操作原子性,直接替换你原有的Team判断+创建逻辑即可:

public function create_team(Request  $request)
{
    $user=User::where('username',$request->username)->first();
    $week = Week::where('status','active')->first();
    $week_id = $week->id;
    $club = Club::where('club',$request->club)->first();

    // 原子查询或创建Team,不需要自己写if判断
    $team = Team::firstOrCreate(
        // 查询条件:同一个用户同一个活动周仅生成一个Team
        ['user_id' => $user->id, 'week_id' => $week_id],
        // 新建时需要填充的额外字段
        ['team_name' => '', 'season_id' => 1]
    );

    // 直接写入关联的俱乐部信息
    UserTeam::create([
        'team_id'=> $team->id,
        'club_id'=> $club->id,  
    ]);

    return response()->json(['message' => 'Succed']);
}

3. 高并发场景可选优化:加请求锁

如果接口并发量极高,可以在请求入口加用户级锁,保证同一个用户的创建请求串行执行:

Cache::lock("create_team_{$user->id}", 10)->get(function () use ($user, $week_id, $club) {
    // 把原有创建逻辑放在锁闭包内执行即可
});

4. 前端逻辑优化(可选)

你当前的Flutter代码是循环发送12个独立请求,可优化为把整批俱乐部数据打包成一个请求发送到后端,后端批量插入user_teams记录,从根源上避免并发问题,还能减少网络请求开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 20:30:03