gpt4 book ai didi

c# - 跨作用域 DbContext 的并发

转载 作者:太空宇宙 更新时间:2023-11-03 19:41:32 32 4
gpt4 key购买 nike

我有一个标准的 ASP.NET Core 2.0 Web API 和一个标准的 DI DbContext:

services.AdDbContext<TestContext>( ... );

我知道我的上下文将添加一个范围内的生命周期,这实际上意味着每次我的 API 收到新请求时,它都会创建一个新的上下文实例。

到目前为止一切顺利。

现在,我创建了一个名为 TestRepository 的存储库,其中包含以下内容:

public class TestRepository : ITestRepository {
public TestContext _context;
public TestRepository(TestContext context) {
_context = context;
}

public async Task IncrementCounter() {
var row = await _context.Banks.FirstOrDefaultAsync();
row.Counter += 1;
await _context.SaveChangesAsync();
}
}

所以它基本上只是将列中的值增加 1 - 异步。 ITestRepository 被添加到服务 IoC 并在需要的地方注入(inject)。

场景:

用户 A 调用 API,获取 TestContext 的新实例,然后调用 IncrementCounter 方法。

调用 SaveChangesAsync 之前,用户 B 调用了 API,获得了新的 TestContext,并且还调用了 IncrementCounter 方法。

现在 用户 A 将值 1 保存到列中,而 用户 B 也认为它应该保存值 1 但它实际上应该是 2

即使阅读了相关文档,我仍然不确定如何保证 IncrementCounter 方法正确递增,即使多个用户使用他们自己的 TestContext< 实例调用 API/强>。

我可能比我应该的更困惑自己,但有人可以澄清如何处理同一上下文的不同实例之间的并发吗?

相关文档:

更新 1

我考虑过在新的“rowVersion”属性上实现 [TimeStamp] 数据注释,然后捕获 DbConcurrencyException,正如相关文档所解释的那样,但这是否解决了它是一个作用域 DbContext 并因此不同上下文的问题正在尝试 SaveChangesAsync()?

最佳答案

这实际上与对象生命周期、作用域或其他方面没有任何关系。并发就是并发。执行诸如递增计数器之类的操作本质上不是线程安全的,因此您必须使用锁或乐观并发,就像处理任何其他线程不安全的任务一样。数据库锁通常不受欢迎,因此乐观并发绝对是首选方法。

这在数据库级别上的工作原理是您基本上有一个时间戳列,它会随着每次更改而更新。 EF 足够聪明,可以监视此列,如果更新时它的值与您第一次查询该行时的值不同,它就会中止更新。此时,您的代码会捕获异常并通过重新查询该行并尝试再次更新它来处理它。

例如,用户 A 和用户 B 试图同时保存值 1。假设用户 B 提前几毫秒到达并成功更新了该列。这也会更新时间戳列。当用户 A 的更新到达时,更新失败,因为时间戳列不再匹配。这会冒泡回 EF,并在其中引发 DbUpdateConcurrencyException。您的代码捕获此异常,并通过重新查询行来响应,其中列现在为 1 而不是 0(并获取最新的时间戳),递增到 2,然后再次尝试保存。这一次,没有其他用户做任何事情,所以它成功通过了。但是,您也可能有另一个并发异常。在这种情况下,您需要冲洗并重复,最终尝试将 3 保存到色谱柱中,依此类推。

您已经链接到问题本身中的所有相关文档,因此我建议您只需花一些时间来完成所有这些并真正理解它。您需要向存储增量值的实体添加一个新属性:

[Timestamp]
public byte[] Version { get; set; }

有了它(显然在迁移之后),EF 将在发生冲突时开始在保存时抛出异常,如上所述。要捕获和处理这些,我建议使用像 Polly 这样的库.它允许您设置重试策略,使处理这种重复的查询-增量-保存逻辑变得微不足道。

关于c# - 跨作用域 DbContext 的并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52613620/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com