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

ASP.NET 6.0+EF+MySQL并发场景下如何避免重复记录生成?

解决ASP.NET 6.0并发请求下MySQL重复群组记录问题

你的问题是典型的竞态条件:并发请求同时执行「查询是否存在→插入新记录」的逻辑,导致多个请求都判定记录不存在,最终重复插入。以下是可靠的解决方案:

1. 数据库层面添加唯一约束(最根本)

仅给name字段加普通索引不够,必须添加唯一约束,让数据库直接拦截重复插入操作,这是最底层的保障。

执行MySQL语句添加唯一约束:

ALTER TABLE groups ADD CONSTRAINT uc_group_name UNIQUE (name);

应用层处理逻辑:捕获MySQL的唯一键冲突异常(错误码1062),此时查询并返回已存在的群组即可。示例代码:

try
{
    var newGroup = new Group { Name = groupName };
    _dbContext.Groups.Add(newGroup);
    await _dbContext.SaveChangesAsync();
    return newGroup;
}
catch (DbUpdateException ex) when (ex.InnerException is MySqlException mysqlEx && mysqlEx.Number == 1062)
{
    // 唯一键冲突,查询已存在的群组
    return await _dbContext.Groups.FirstOrDefaultAsync(g => g.Name == groupName);
}

2. 事务加行级锁(避免竞态查询)

在查询是否存在时,使用行级锁锁定查询范围,阻止其他并发事务插入相同名称的群组。适合需要严格控制流程的场景。

EF Core示例代码:

using var transaction = await _dbContext.Database.BeginTransactionAsync(System.Data.IsolationLevel.RepeatableRead);
try
{
    // 使用FOR UPDATE锁定查询结果(若不存在则锁定间隙,防止插入相同值)
    var existingGroup = await _dbContext.Groups
        .FromSqlRaw("SELECT * FROM groups WHERE name = {0} FOR UPDATE", groupName)
        .FirstOrDefaultAsync();
    
    if (existingGroup != null)
    {
        await transaction.CommitAsync();
        return existingGroup;
    }

    var newGroup = new Group { Name = groupName };
    _dbContext.Groups.Add(newGroup);
    await _dbContext.SaveChangesAsync();
    await transaction.CommitAsync();
    return newGroup;
}
catch
{
    await transaction.RollbackAsync();
    throw;
}

注意:需确保MySQL表使用InnoDB引擎(默认支持事务和行级锁)。

3. 缓存配合数据库约束(优化性能)

之前的缓存方案失效,是因为没有和数据库操作强一致。正确的缓存逻辑应该是:

  • 查询时先读缓存,若存在直接返回
  • 缓存不存在则走「数据库加锁查询/插入」流程
  • 插入成功后再将群组信息写入缓存
  • 若捕获到唯一键冲突,查询到已存在的群组后再写入缓存

这样既利用缓存提升性能,又通过数据库约束和锁保证数据一致性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:22:10