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

Laravel中使用save()操作数据库时出现重复数据及死锁问题求助

问题解决方案

一、解决重复Item记录问题

重复插入的核心原因是并发场景下,多个事务同时执行Item的插入操作,且未做唯一性校验,需从代码+数据库两层做防护:

  1. 数据库层面:添加唯一约束
    给items表的field字段添加唯一索引(假设field是业务上的唯一标识),从底层阻止重复数据插入:
ALTER TABLE items ADD UNIQUE INDEX idx_items_field (field);
  1. 代码层面:使用firstOrCreate替代直接新建保存
    Laravel的firstOrCreate会先按条件查询,不存在则创建,内部会处理并发场景的锁竞争,避免重复插入:
public function saveData($data1, $data2)
{
    DB::beginTransaction();

    try {
        // 按field查询,不存在则创建,确保相同data1仅生成一条Item
        $item = Item::firstOrCreate(
            ['field' => $data1], // 唯一匹配条件
            ['field' => $data1]  // 插入时的字段值
        );

        $related = new Related;
        $related->item_id = $item->id;
        $related->field = $data2;
        $related->save();

        DB::commit();
    } catch (\Throwable $e) {
        DB::rollBack();
        throw $e;
    }

    return $item;
}

二、解决Related插入时的死锁问题

死锁通常源于锁竞争顺序不一致或缺失索引导致全表锁,可通过以下方式解决:

  1. 给Related表添加索引
    确保relateds表的item_id字段存在普通索引,避免插入时触发全表扫描加表锁:
ALTER TABLE relateds ADD INDEX idx_relateds_item_id (item_id);

如果业务上item_id和field的组合是唯一的,建议添加联合唯一索引,进一步减少锁冲突:

ALTER TABLE relateds ADD UNIQUE INDEX idx_relateds_item_field (item_id, field);
  1. 改用updateOrCreate避免重复关联数据
    若不允许同一Item下存在相同field的Related,用updateOrCreate替代直接新建,减少不必要的插入操作,降低锁竞争:
// 替换原有的Related新建保存代码
$related = Related::updateOrCreate(
    ['item_id' => $item->id, 'field' => $data2], // 唯一匹配条件
    ['item_id' => $item->id, 'field' => $data2]  // 插入/更新的字段值
);
  1. 缩短事务执行时间
    确保事务内仅包含必要操作,避免耗时逻辑,减少锁的持有时间,降低死锁概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 08:48:09