请解释为什么在进行CQRS,ES和DDD时,同时修改多个聚合是一个坏主意。有什么情况下它还可以吗?
以PurgeAllCompletedTodos等命令为例。我希望此命令导致一个事件,通过将IsActive设置为false来更新每个已完成的Todo聚合的状态。
为什么这不好?
我能想到的一个原因:
更新域状态时,将事务限制在整个状态的明确定义的部分可能是好的,这样在更新期间只需要对此部分进行写锁定。这样做可以在并行的不同聚合上进行多次写入,这可以在一些非常繁重的情况下提高性能。
答案 0 :(得分:19)
问题的回答在于"聚合"的含义。
首先我会说你没有修改' n'聚合,但你正在修改' n'实体。
聚合包含多于一个的实体,它只是一个事务概念,当您需要修改多个实体的状态时,会使用聚合(模式)< / strong>在您的应用程序中事务性地(所有都被修改或没有)。
现在,为什么要用一个命令修改多个聚合?
如果您认为有这种需要,在执行任何其他操作之前,请检查您的聚合边界,看看您是否可以修改它以删除对1命令的需求 - &gt; &#39; N&#39;骨料。
聚合可以包含许多相同类型的实体,因此对于您的命令 PurgeAllCompletedTodos ,您还可以考虑将事务边界从单个 Todo 扩展到包含所有用户待办事项的聚合 UserTodosAggregate ,让它管理单个用户待办事项的所有命令。
通过这种方式,您可以在单个事务中修改用户的所有待办事项。
如果这仍然无法解决您的问题,因为,让我们说需要清除应用程序中每个用户的所有已完成的待办事项,您仍然需要向&#39; ñ&#39;聚合,聚合边界没有帮助,因此我们可以考虑使用 AllApplicationTodosAggregate 来管理命令。
可能这不是最好的解决方案,因为正如你所说的那样,命令会阻止应用程序的所有待机,但是,总是检查它是否是一个很好的权衡(这部分阻塞在很好地解释了蓝皮书和DDD红皮书。
如果我需要修改某些实体并且不能将它们放在一个聚合中,该怎么办?
如前所述,由于事务,修改多个聚合的命令很糟糕。如果您修改3个聚合,第一个是好的,然后服务器关闭怎么办?
在这种情况下,您正在进行的是需要进行大量单一修改以防止系统不一致。 它可以使用流程管理器来完成,流程管理员负责修改所有聚合,向他们发送正确的命令,并在发生故障时管理故障。
聚合仍然会收到它自己的命令,但是进程管理器负责以它知道的方式发送它们(一个是时间,一个并行,每次5个,你想要什么? )
因此,您可以制定策略来管理两个事务之间的故障,并做出如下决定:&#34;如果出现故障,请回滚所有已完成的修改,直到现在为止#34; (向每个聚合发送回滚命令),或者&#34;如果操作失败,每30分钟重复3次,如果操作失败,则回滚&#34;,&#34;如果失败则创建通知对于系统管理员&#34;。
(对不起这篇长篇文章,至少希望它有所帮助)