当您希望代码在竞争条件下工作时,通常开发人员使用乐观并发控制(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/
指出这是一个“标准”感谢问题描述中的任何差距。提前谢谢!
答案 0 :(得分:12)
尝试将事件附加到流时,您可以指定预期的当前版本号,并在实际当前数字与其匹配时抛出。
这种乐观并发机制是built into一些事件存储系统。
您链接的文章似乎描述了类似的方法,但更强大,因为您可以访问自预期版本以来发生的事件类型,并且可以根据更细粒度的标准检测冲突。
答案 1 :(得分:3)
应用事件源您还应该在表中有一个版本字段,否则在构建聚合根时无法获取事件的顺序。但顺序很重要。您还可以使用此版本字段来支持OCC。 例如,如果您有一个竞争条件,例如具有相同ID的两个事件,并且相同的版本将在事件存储中几乎同时保存,则最后一个丢失,如果使用复合,将引发重复键异常主键由聚合ID和版本组成。
答案 2 :(得分:3)
默认乐观锁定不适用于事件来源,因为乐观锁定需要 状态 锁定。在事件采购中,您没有像州一样的东西,您只需拥有事件列表(更改流)。 正如之前已经提到的那样,您可以使用以下方法:
还请记住,您的事件存储应该允许您使用唯一索引,在这种情况下,RDBMS表是最佳选择。