我遇到了一些竞争条件,其中数据库中的一行可能由两个线程同时创建。为了解决这个问题,我实现了重试,如下所示:
int retries = 0;
while (true)
{
try
{
var saved = context.Table.FirstOrDefault(x => x.field1 == val1 && x.field2 == val2);
if (saved != null)
{
//edits saved
}
else
{
context.Table.Add(new Table
{
field1 = val1,
field2 = val2
});
}
await context.SaveChangesAsync();
return Json(true);
}
catch (Exception e)
{
if (retries >= 5)
throw (e);
retries++;
}
}
不知何故,连续失败 5 次,并出现相同的错误:
Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常。---> System.Data.SqlClient.SqlException:无法在具有唯一索引“IX_Table_field1_field2”的对象“dbo.Table”中插入重复的键行。重复的键值为(val1, val2)。
即使数据库中明确存在该行,为什么 FirstOrDefault 返回 null?我正在使用 Microsoft.AspNetCore.All v.2.1.4
上下文不在线程之间共享。当多个 HTTP 请求同时到达时,就会发生竞争。上下文被注入到控制器(此代码所在的位置)。它使用默认设置通过 AddDbContext 调用进行注册,使其具有 ServiceLifetime 作用域。
添加但未保存的行保留在上下文中并继续尝试插入。我保留了对新行的引用并将其添加到 catch 块中:
context.Entry(NewRow).State = EntityState.Detached;
守着一只汪
侃侃无极
largeQ