- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个标准的 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/
这是我的本地域名 http://10.10.1.101/uxsurvey/profile/dashboard 在 Controller 中,我为用户列表设置了一个操作 redirect(control
要处理 Canonical URL,最佳做法是执行 301 重定向还是更好地为 www 和非 www 域使用相同的 IP 地址? 例如: 想要的规范 URL/域是 http://example.com
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
我想创建一个 weblogic 集群,其中有两个托管服务器,每个服务器在物理上独立的远程计算机上运行 根据weblogic文档 All Managed Servers in a cluster mus
我正在运行 grails 3.1.4,但在创建允许我将多个域对象绑定(bind)到其他几个域对象的模式时遇到了问题。作为我正在尝试做的一个例子: 我有三个类(class)。书籍、作者和阅读列表。 作者
我试图使用@count函数来根据它获取数据,但是在没有崩溃报告的情况下它以某种方式崩溃了。 这是代码 class PSMedia: Object { @objc dynamic var id
有谁知道是否有办法只输入字母字符而不输入数字?我想过这样的事情 CREATE DOMAIN countryDomain AS VARCHAR(100) CHECK( VALUE ??? );
我的代码: const checkoutUrl = 'https://example.com/checkout/*' window.onload = startup() function st
一些不是我编写的应用程序,也不是用 PHP 编写的,它为域 www.example.com 创建了一个 cookie。 我正在尝试替换该 cookie。所以在 PHP 中我做到了: setcookie
什么是 oauth 域?是否有任何免费的 oauth 服务?我可以将它用于 StackApps registration 吗? ?我在谷歌上搜索了很多,但找不到答案。 最佳答案 这是redirect_
自从 In October 2009, the Internet Corporation for Assigned Names and Numbers (ICANN) approved the cre
我使用 apache 作为我的应用程序 Web 服务器的代理,并希望即时更改与 sessionid cookie 关联的域名。 该cookie有一个与之关联的.company.com域,我想使用apa
我只想托管一个子域到cloudflare。我不想将主域名的域名服务器更改为他们的域名服务器。真的有可能吗? 最佳答案 是的,这是可能的,但是需要通过CloudFlare合作伙伴进行设置,或者您需要采用
When using socket in the UNIX domain, it is advisable to use path name for the directory directory m
想象两个共享一个域类的 Grails 应用程序。也许是 Book 域类。 一个应用程序被标识为数据的所有者,一个应用程序必须访问域数据。类似于亚马逊和亚马逊网络服务。 我想拥有的应用程序将使用普通的域
我有一个包含字段“URL”的表单。第一部分需要用户在文本框中填写。第二部分是预定义的,显示在文本框的右侧。 例如,用户在文本框中输入“test”。第二部分预定义为“.example.com”。因此,总
如果我要关闭并取消分配 azure 中的域 Controller ,从而生成新的 vm Generationid,我需要采取哪些步骤来恢复它? 最佳答案 what steps do I need to
我想尝试使用 Azure 作为托管提供商(我有一个域)。我读过那篇文章https://learn.microsoft.com/en-us/azure/app-service-web/web-sites
所以.... 我想知道是否有人可以在这方面协助我? 基本上,我已经创建了一个自托管的Docker容器,用作构建代理(Azure DevOps) 现在,我已经开始测试代理,并且由于我们的放置文件夹位于W
我是一名优秀的程序员,十分优秀!