CQRS与CQS之间的区别


70

我正在学习什么是CQRS模式,并且知道还有CQS模式。

当我尝试搜索时,我发现了很多关于CQRS的图表和信息,但没有发现太多有关CQS的信息

CQRS模式的关键点

在CQRS中,有一个完全独立的模型(命令模型)和一个模型(查询模型)编写。

CQRS图

CQS与CQRS有何不同?

Answers:


85

CQS(命令查询分离)和CQRS(命令查询责任分离)非常相关。您可以认为CQS处于类或组件级别,而CQRS则更多地处于受限上下文级别。

我倾向于认为CQS在微观层面,而CQRS在宏观层面。

CQS规定了用于查询模型或向模型写入的单独方法:查询不改变状态,而命令改变状态但不具有返回值。它是由Bertrand Meyer设计的,是他在Eiffel编程语言方面的开创性工作的一部分。

CQRS规定了类似的方法,只是它更多地是通过系统的路径。查询请求采用与命令不同的路径。该查询将返回数据,而不会更改底层系统。该命令更改系统,但不返回数据。

格雷格·杨(Greg Young)对几年前的CQRS进行了非常详尽的撰写,并探讨了CQRS是CQS的演变。该文档几年前向我介绍了CQRS,我发现它仍然是非常有用的参考文档。


1
这是两者之间的明显区别。谢谢。
CA Arefe

19

这是一个古老的问题,但我要回答一下。我不经常在StackOverflow上回答问题,因此,如果我在社区范围之外做一些事情,例如链接到事物,写长答案等,请原谅我。

CQRS和CQS之间有很多区别,但是CQRS在其定义内使用CQS!让我们先定义两者,然后讨论差异。

CQS根据消息的返回值定义了两种类型的消息:没有返回值(无效)表示这是一条命令;返回值(非void)指定此方法为查询。

  • 命令更改信息
  • 查询返回信息

命令更改状态。查询不。

现在是CQRS,它使用与CQS相同的命令和查询定义。CQRS所说的是我们不希望使用Command和Query方法的对象。相反,我们需要两个对象:一个包含所有命令,一个包含所有查询。

总的来说,这个想法很简单。这一切后,这样做,事情变得有趣。在线上有很多演讲,我讨论了一些相关的属性(很抱歉,此处无法键入!)。


6

最大的区别是CQRS使用单独的数据存储来存储命令和查询。查询存储可以使用诸如文档数据库之类的不同技术,也可以只是同一数据库中的非规范化架构,这使得查询数据更加容易。

数据库之间的数据通常使用服务总线之类的方法异步复制。因此,查询存储中的数据最终是一致的(在某个时间点将在那里)。应用程序需要考虑到这一点。虽然可以在两个存储中使用相同的事务(相同的数据库或两阶段提交)进行写入,但是出于可伸缩性的原因,通常不建议这样做。

CQS体系结构从相同的数据存储/表读取和写入。


11
为避免疑问,CQRS在应用时允许您使用单独的数据存储,但这不是必需的。您仍然可以通过一个数据存储“执行CQRS”。
Neil Barnwell

格雷格·杨(Greg Young)多次提到了最终的一致性,但是似乎始终没有得到SO的答案(这是我所看到的。)
johnny

6

阅读发明家Greg Young的答案

我认为,像“依赖注入”一样,这些概念是如此简单且被认为是理所当然的,以至于它们拥有奇特的名称这一事实似乎使人们认为它们比实际的要重要得多,特别是因为CQRS通常与事件源一起被引用。

  • CQS是将读取方法更改为更改状态的方法的分离;请勿同时使用两种方法。这是微观层面。

  • CQRS将这一概念扩展到了机器-机器API的更高层次,消息模型和处理路径分离。

因此,CQRS是您应用于API或Facade中的代码的原则。

我发现CQRS在SOLID中本质上是非常强大的S,将这种分离深深地吸引到开发人员的头脑中,以产生更多可维护的代码。

我认为Web应用程序不适合CQRS,因为通过表示传递进行状态改变意味着命令和查询是同一请求响应的两个方面。表示形式是命令,响应是查询。

例如,您发送一个订单并接收所有订单的视图。

想象一下,网站的代码是否被分解为命令方和查询方。路由动作处理代码将需要落入这些方面之一,但两者都需要。

设想更严格的隔离,如果将代码移到两个不同的可编译代码库中,则该网站将接受某种形式的POST,但是用户必须浏览到另一个网站URL才能查看此操作的影响。这显然是疯狂的。一种解决方法是始终重定向,尽管这并不是真正的RESTful,因为理想的REST应用程序是下一个表示形式包含超文本来驱动下一个状态转换的地方,依此类推。

假定网站是人与机器(或机器与机器)之间的REST API,尽管其他类型的HTTP消息传递API可能非常适合CQRS,但网站也包括REST API。

尽管动作处理程序位于该边界之外,但网站范围内的服务或外观显然可以与CQRS很好地配合使用。

在Wikipedia上查看CQS


我只是随机遇到这个问题,想补充一点。您提到“我认为Web应用程序不适合CQRS,因为通过表示传递进行状态改变意味着命令和查询是同一请求-响应的两个方面。表示是命令,而响应是查询。” 这实际上是一个常见的声明!让我问一下,您是否看过原子馈源的工作原理?可以说多少个数据类似于原子馈送?
格雷格·杨

格雷格(Greg),您好,我开始写作,然后停下脚步,认为如果您回答了OP的问题,我们将为您提供更好的服务。我希望其他当局能够加快SO清理的进度。我经常不确定。我常常无法从第五手的观点或合理的听起来的解释中分辨出什么是正确的,我常常会学习艰难的方法。我客户的15个开发人员使用CQRS代码结构构造了许多API中的每一个,这与我的理解相矛盾,因为像网站一样,命令端的POST处理程序还执行许多查询以构造丰富的返回视图和有效的下一步操作链接。
路加·普普利特

1
这里已经有一个或两个链接可以链接我在这个主题上的资料,这就是为什么我没有(不得不剪掉)“如果将代码移到两个不同的可编译代码库中,则可以想象到更强的隔离性。” REST的问题比说CQRS要好。没有什么可以说明如何处理数据的。POST可能用于创建事件/ streams / {stream}似乎是目标(您同意吗?)。GET可能会转到/ streams / {stream}以获取信息。没有什么指定该资源的所有请求必须由相同的服务等进行处理
Greg Young的

1
如果不清楚(抱歉,简短的评论),那么它也很常见,POST会返回URI,然后客户端应针对最新状态通知(考虑异步处理)向其发出GET
Greg Young,

谢谢格雷格。我同意。我确实了解您在发布事件和使用提要方面的想法,但是如果您在答案中可以写得更多的内容进行解释,那是最好的选择。在每个突变中都返回303通常不是RESTful的,在这种情况下,状态转换通常会通过包含一个或多个其他链接或形式的响应来满足,因此这属于“其他类型的HTTP消息传递API可能非常适合CQRS “ 我认为。
路加·普普利特

5
  • CQS与命令和查询有关。它不在乎模型。您以某种方式分离了用于读取数据的服务,以及用于写入数据的其他服务。
  • CQRS关于写和读的单独模型。当然,使用写入模型通常需要读取一些内容才能满足业务逻辑,但是您只能对读取模型进行读取。单独的数据库是最新技术。但是,请想象单个DB具有针对ORM建模的读写模型的单独模型。通常足够好。

我发现人们经常说他们有CQS时就会练习CQRS。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.