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

Azure应用并发插入重复数据:为何校验逻辑仍无效?

问题根源与解决方案

你的代码出现重复记录的核心原因是并发竞争条件:当多个客户端请求同时到达时,它们的「查询是否存在」操作会在对方的「插入记录」操作完成前执行,导致两个请求都判定记录不存在,最终都执行插入,产生重复条目。

以下是具体的解决方法:

1. 数据库层面添加唯一约束(最可靠的底层保障)

直接在Order表上给CustomerId和ExternalId的组合添加唯一约束,这是阻止重复的终极防线——即使应用层校验失效,数据库会直接拒绝重复插入。

以SQL Server为例,执行以下SQL语句:

ALTER TABLE Orders 
ADD CONSTRAINT UQ_Orders_CustomerId_ExternalId 
UNIQUE (CustomerId, ExternalId);

2. 改用数据库原子操作替代应用层分步校验

将「查询+插入」合并为数据库的原子操作,利用数据库的事务特性避免并发竞争。可以通过EF Core执行原生SQL实现:

var affectedRows = await _dataContext.Database.ExecuteSqlRawAsync(
    "INSERT INTO Orders (ExternalId, CustomerId) " +
    "SELECT @externalId, @customerId " +
    "WHERE NOT EXISTS (SELECT 1 FROM Orders WHERE CustomerId = @customerId AND ExternalId = @externalId)",
    new SqlParameter("@externalId", message.externalId),
    new SqlParameter("@customerId", message.customerId));

if (affectedRows == 0)
{
    // 记录已存在,无需执行后续操作
}

这种方式让数据库在同一操作内完成检查和插入,彻底避免并发竞争。

3. 检查DbContext的生命周期配置

如果你的DbContext是单例或者生命周期过长,会导致上下文缓存旧数据,查询时可能读取的是缓存而非最新的数据库状态。确保在ASP.NET Core等框架中,DbContext使用Scoped生命周期(默认配置),每个请求创建独立的上下文实例,保证查询总是访问最新数据。

4. 捕获并处理唯一约束冲突异常

添加唯一约束后,并发插入时会抛出DbUpdateException,你需要在代码中捕获该异常并处理:

try
{
    await _dataContext.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
    if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2601)
    {
        // 处理重复记录场景,比如返回客户端「记录已存在」的提示
    }
    else
    {
        throw; // 其他异常正常抛出
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 08:07:14