【发布时间】:2018-11-07 10:23:48
【问题描述】:
我有以下(轴突)聚合体:
@Aggregate
@NoArgsConstructor
public class Car{
@AggregateIdentifier
private String id;
@CommandHandler
public Car(CreateCar command){
apply( new CarCreated(command.getId()) );
}
@EventSourcingHandler
public void carCreated(CarCreated event) {
this.id = event.getId();
}
}
我可以通过提交带有特定 ID 的 CreateCar 命令来创建汽车,从而引发 CarCreated 事件。太好了。
但是,如果我发送另一个具有相同 ID 的 CreateCar 命令,则该命令无法通过聚合验证(给定 ID 已经存在)。随后,它将简单地触发一个新的CarCreated 事件。这是一个谎言。
如果汽车已经存在,确保CreateCar 命令失败的最佳方法是什么?
当然,我可以先检查存储库,但这不会阻止竞争条件...
【问题讨论】:
-
使用 UUID 或在数据库中生成 id
-
这如何防止发生两个 CarCreated 事件?
-
不能将具有相同聚合标识符的相同创建事件保存在事件存储中,因此该事务应该在数据库级别失败,并被回滚。我怀疑您正在使用 UUID 作为聚合标识符,并且实际上希望聚合对另一个标识符也有唯一约束。在这种情况下,就轴突而言,您正在创建一个新的唯一聚合,它恰好具有与另一个相同的有效负载。您必须使用锁定解决此问题并读取查询表。
-
这通常使用乐观并发来处理。当向您的存储技术发送事件时,您应该将预期的事件索引与事件一起发送。对于您创建的事件,该事件将为 0(对于基于 0 的系统)。您的存储技术有望支持这一点,并将检查索引为 0 的事件是否尚未存储,否则会失败。您可以通过补充聚合获得当前事件指数。看,当您获得聚合的事件时(在处理命令之前),您只需计算事件的数量并将其用作预期的事件索引。