【问题标题】:updating query part in CQRS更新 CQRS 中的查询部分
【发布时间】:2016-11-27 08:38:26
【问题描述】:

我已经阅读了很多关于 CQRS 的文章,还有一件小事我仍然无法理解。到处都写着有两种模型(它们甚至可能有两种不同类型的数据存储)。其中一个模型称为write 模型,另一个模型是read

流程如下:例如,写入模型进行一些更改,将这些更改存储到(自己的)数据库中,然后触发一个事件。然后read 模型,必须订阅此类事件,处理它并更新自己的投影 这是正确的吗?如果是,那么这基本上意味着人们称之为read 模型的东西不仅仅是从存储中读取。

我错过了什么? 主要问题是哪个部分负责更新预测/查询部分?

附:谢谢你们的回复!现在拼图已经组装好了:-)

【问题讨论】:

  • 我想说的很简单——正如其中一个答案中提到的,这些术语——读和写,仅适用于公共接口。当然,内部从写入模型读取并写入读取模型。通常,您拥有读取和写入写入模型的聚合存储库以及读取和写入读取模型的投影。写入模型中每次更新的本质都被发送到投影,然后可以更新读取模型(通过写入!)

标签: architecture domain-driven-design cqrs


【解决方案1】:

如果是,那么它基本上意味着人们所说的阅读模式,而不是只读模式。

大部分正确。

写入模型中的实体有一个包含写入方法的公共接口,但它们还包括一个复制当前状态(读取)的受限接口。读取模型中的实体有一个包含读取方法的公共接口,但也包括一个替换当前状态的受限接口(写入)。

中间有一个过程,使用受限接口读取写模型的状态,将其从写优化的数据结构转换为读优化的数据结构,然后使用受限接口写入这个新的状态到读取模型。

我认为引入与模型不同的商店的概念很有用。写入模型对写入存储(又名记录簿)进行更改,读取模型使用读取存储发布的状态来回答查询,并使用受限接口链接两个存储;这在写入模型和读取模型之间建立了桥梁。

在这种情况下,存储可能只是在内存中;例如,在 java 中,您可以通过将 volatile 句柄更新为读取优化的数据结构来更新读取存储。数据模型中的方法只获取数据结构的最新可用版本,并继续使用该副本直到查询完成(确保读取模型产生内部一致的查询结果)。

您通常希望将中间过程与写入模型本身的更新分离。它可能是事件驱动的(当我们看到一个领域事件时,构建一个由该事件更改的读取优化数据结构的新副本,然后发布它们)。它可能会被安排(每隔一段时间,查询记录簿中的领域事件,并处理我们尚未看到的事件)。事件本身可能包含重建读取结构所需的所有状态(如果您在写入模型中使用事件溯源,这很可能),或者事件可能只是识别已更改的聚合,并且过程需要查询记录簿以查找所有相关状态。

有很多选择,但它们往往遵循相同的基本模式。

【讨论】:

    【解决方案2】:

    我的理解方式……

    写入/命令端是域模型,负责确保系统处于正确状态 - 如果使用 DDD,则通过聚合。您加载聚合并应用一些行为。这是您的业务规则和行为存在的点。这也是您引发领域事件的地方。这是一个很好的方法(尤其是结合事件溯源,您的数据库 是您的事件)。但是,我不相信 CQRS 要求使用事件。例如,您可以只更新 sql 数据库中的某些状态。命令端用于保护域的不变量,

    然后读取必须订阅此类事件的模型,处理它并更新自己的投影,这是正确的吗?

    如果您使用事件,是的。但是,请参见下文...

    如果是,则基本上意味着人们称之为读取模型的东西不仅仅是从存储中读取。

    这取决于您的存储空间以及您“创建”读取模型的方式。您可以订阅事件,然后更新某些数据库中的读取模型(可能是 SQL 数据库中的表、文档数据库中的文档)或内存中的对象模型。然后,您可以通过从数据库或内存模型中加载这些读取模型来查询它们。

    但是,您也可以在没有事件的情况下进行 CQRS。在这种情况下,读取模型的概念可能只是一个数据库查询。即 SQL 查询。从与您的写入端相同的存储中读取。

    例如,API 或网页请求进来,您对数据库执行查询,然后将结果返回给用户。此查询不通过域模型。您仍然将读取与写入分开,只是没有使用事件。

    主要问题是负责更新预测/查询部分的部分是什么?

    如果您使用事件,它将是事件的订阅者。您将监听事件,然后更新您的读取模型。这些的实际实现将取决于您的架构。例如,如果使用EventStore,则客户端已内置支持subscribers 的概念。例如,这些可以在简单的控制台应用程序中或在 API 中实现。

    这个流程可能是这样的:

    • 应用启动
    • 订阅 N 个事件流
    • 当您收到事件、更新数据库或内存模型时

    如果您不使用事件,那就不同了。您的架构可能足够简单,以至于读取端只查询数据库(从命令端来说已经是最新的!)。

    【讨论】:

    • 也许这有点离题,但是您如何在新添加的 1...N 实例上重建查询模型,另外部署到活动集群。从操作开始,我有 3 个查询模型是最新的服务。现在我检测到重负载即将到来,因此我触发了部署额外 10 个实例的操作,每个实例都带有自己的本地数据库,仅用于查询。如何使用过去的所有查询就绪数据刷新这些数据库,而不仅仅是新事件?
    猜你喜欢
    • 2011-01-02
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    相关资源
    最近更新 更多