RavenDB并发、锁定文档等

本文关键字:文档 锁定 并发 RavenDB | 更新日期: 2023-09-27 17:59:39

我不能100%确定如何解决这个问题,所以我将首先说明我的问题。请忽略这是一个糟糕的例子或数据结构的糟糕设计,因为这只是一个例子。

想象一下,我们有一个名为Person的类。Person类具有您期望的标准属性(Name、Age等)。它还有一个简单的PersonId和一个CompanyId。此外,它还有一个名为Code的特殊属性。

在业务案例中,代码需要针对每个CompanyId是唯一的。因此,它本质上是CompanyId+Code的复合密钥结构。

我需要这样做,当有并发应用程序创建这些Person实体时,它们需要能够遵守这个约束。

我已经研究了各种方法来解决这个问题:

1) 我知道有一个Raven UniqueConstraints插件可以支持其中的一些场景,但在这种情况下,我想避免使用插件

2) 起初,我认为将Person文档的raven ID作为CompanyId+Code的复合密钥。但是,业务需要允许用户更改代码。因此,这意味着如果用户编辑代码,我们最终将创建一个新的Person记录,该记录的CompanyId+NewCodeSpecified将作为新的复合键ID。然后,上一个记录仍将浮动。我当然可以删除,但感觉有点脏?

3) 我坚持使用唯一的个人Id,当任何应用程序到达端点创建新的个人时,我会从raven中读取,看看是否有包含我想要创建的相同公司Id和代码的个人记录。所以它会是这样的:

  • 读取人员记录
  • 人员记录不存在
  • 继续创建新的人员记录

当然,在简单场景的中也没问题

但是,如果我们遇到了两个应用程序同时运行并同时访问API服务(这是负载平衡的)的罕见情况,该怎么办。

那么它会像:

App1                           App2
-----                          ----
Read person record             Read person record
Verify it does not exist yet   Verify it does not exist yet
Proceed to save new person     Proceed to save new person

因此,他们最终都会制作一个具有相同公司Id+代码的个人记录。

我知道UseOptimisticConcurrency选项,但我相信只有当他们都试图修改同一记录,并且ETAG检查启动SaveChanges时,它才会抛出ConcurrencyException。

因此,我有点困惑于如何应对这种情况。

RavenDB并发、锁定文档等

在这里冒险,但。。。

您可以制作一个名为CodeConstraint的新文档。我见过NServiceBus Saga持久性做类似的事情。它看起来像这样:

public class CodeConstraint
{
   public string Id { get; set;} //you manually provide the id
   public string PersonId { get; set;}
}

然后创建一个Person,然后创建CodeContraint,并将代码约束分配给Person。您可以将其封装到TransactionScope中,这样就不会有孤立文档,以防它无法写入。

此外,因为这是它自己的文档,如果您有任何竞争条件,Raven将为您提供并发异常。

如果用户想要更改代码。然后创建一个新的"CodeConstraint"并将其分配给Person,并保留或删除旧的。

对于奖金,您可以扩展CodeContraint文档,并为其修改或创建时间戳,因为您提到了您的部分要求是允许用户自定义此代码。