事件采购和乐观并发控制

时间:2016-03-24 12:32:24

标签: domain-driven-design event-sourcing optimistic-concurrency

当您希望代码在竞争条件下工作时,通常开发人员使用乐观并发控制(OCC)。来自维基百科:

  

...在提交之前,每个事务都会验证没有其他事务   事务已修改其已读取的数据。如果检查显示   相互冲突的修改,提交事务回滚......

实现OCC的方法是检查要修改的version数据。如果版本不同,那么其他事务已修改数据,并由应用程序决定如何解决冲突(重新尝试,通知用户......)。

草案如下:

class Repository
{
    public class save($data)
    {
        $currentVersion = $data->version;
        $data->version  = $currentVersion + 1;

        $result = $this->db->update($data, [
            'id'        => $data->id,
            'version'   => $currentVersion
        ]);

        if (1 === $result) {
            // everything ok
        } else {
            // conflict!
        }
    }
}

我的问题是,与EventSourcing中我们只追加域中发生的所有事件一样,我们不能再使用此方法来实现OCC。在使用EventSourcing时,哪种方法可以保留OOC?

一个可行的选项,它可以在存储时查找冲突事件。这种方法允许对事件进行细粒度控制。我不知道这是否会使解决方案复杂化,或者我认为http://danielwhittaker.me/2014/09/29/handling-concurrency-issues-cqrs-event-sourced-system/

指出这是一个“标准”

感谢问题描述中的任何差距。提前谢谢!

3 个答案:

答案 0 :(得分:12)

尝试将事件附加到流时,您可以指定预期的当前版本号,并在实际当前数字与其匹配时抛出。

这种乐观并发机制是built into一些事件存储系统。

您链接的文章似乎描述了类似的方法,但更强大,因为您可以访问自预期版本以来发生的事件类型,并且可以根据更细粒度的标准检测冲突。

答案 1 :(得分:3)

应用事件源您还应该在表中有一个版本字段,否则在构建聚合根时无法获取事件的顺序。但顺序很重要。您还可以使用此版本字段来支持OCC。 例如,如果您有一个竞争条件,例如具有相同ID的两个事件,并且相同的版本将在事件存储中几乎同时保存,则最后一个丢失,如果使用复合,将引发重复键异常主键由聚合ID和版本组成。

答案 2 :(得分:3)

默认乐观锁定不适用于事件来源,因为乐观锁定需要 状态 锁定。在事件采购中,您没有像州一样的东西,您只需拥有事件列表(更改流)。 正如之前已经提到的那样,您可以使用以下方法:

  1. 每个事件都有修订号(事件采购方法中的事件很常见)
  2. 每当发生任何事件并且您需要保存它时,您应该从事件存储中获取最新的修订号
  3. 在事件存储中保存之前,只需增加此修订号
  4. 即可
  5. 确保您在事件存储中具有唯一的修订号索引
  6. 如果两个并行事务增加了上一个修订号(例如5) 并尝试保存两个增加修订号的新事件(在我们的例子中它将是6),其中一个因为唯一索引而失败。
  7. 还请记住,您的事件存储应该允许您使用唯一索引,在这种情况下,RDBMS表是最佳选择。