CQRS 和 CQS 的区别

Difference between CQRS and CQS

我正在学习什么是 CQRS 模式并了解到还有 CQS 模式。

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

CQRS 模式中的关键点

在CQRS中有一种写模型(命令模型)和一种读模型(查询模型),它们是完全分开的。

CQS 与 CQRS 有何不同?

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

我倾向于认为 CQS 是微观层面的,CQRS 是宏观层面的。

CQS 规定了从模型查询或写入模型的不同方法:查询不改变状态,而命令改变状态但没有 return 值。它是由 Bertrand Meyer 设计的,作为他在 Eiffel 编程语言方面的开创性工作的一部分。

CQRS 规定了类似的方法,只是它更多的是通过您的系统的路径。查询请求采用与命令不同的路径。在不改变底层系统的情况下查询 returns 数据;该命令会更改系统但不会 return 数据。

Greg Young 汇总了几年前 CQRS 的 pretty thorough write-up,并探讨了 CQRS 是如何从 CQS 演变而来的。几年前这篇文档介绍了我的CQRS,我觉得它仍然是一个非常有用的参考文档。

最大的区别是 CQRS 为命令和查询使用单独的数据存储。查询存储可以使用不同的技术,如文档数据库,或者只是同一数据库中的非规范化模式,使查询数据更容易。

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

CQS 架构读取和写入相同的数据store/tables。

  • CQS 是关于命令和查询的。它不关心模型。您以某种方式将用于读取数据的服务与其他用于写入数据的服务分开。
  • CQRS 是关于单独的 models 用于写入和读取。当然,写模型的使用往往需要读一些东西来完成业务逻辑,但你只能在读模型上做读。单独的数据库是最先进的。但是想象一下单个数据库具有单独的模型,用于在 ORM 中建模的读取和写入。它通常足够好。

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

阅读发明家 Greg Young 的回答

我认为,像 "Dependency Injection" 一样,这些概念是如此简单并且被认为是理所当然的,以至于它们具有花哨的名字这一事实似乎促使人们认为它们比它们更重要,尤其是 CQRS 是经常与事件溯源一起引用。

  • CQS 是将读取的方法与改变状态的方法分离;不要在一种方法中同时执行这两项操作。这是微观层面。

  • CQRS 将此概念扩展到更高级别的机器-机器 APIs,消息模型和处理路径的分离。

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

我发现 CQRS 本质上是 SOLID 中的一个非常强大的 S,将这种分离深入到开发人员的心理中,以生成更易于维护的代码。

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

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

想象一下,如果网站的代码被分解为命令端和查询端。路由操作处理代码需要落入其中之一,但它同时做到了。

想象一个更强的隔离,如果代码被移动到两个不同的可编译代码库中,那么该网站将接受一个 POST 的表单,但用户将不得不浏览到另一个网站 URL 查看操作的影响。这显然是疯了。一种解决方法是始终重定向,尽管这实际上不是 RESTful,因为理想的 REST 应用程序是下一个表示包含超文本以驱动下一个状态转换等的位置。

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

网站边界内的服务或门面显然可以与 CQRS 一起很好地工作,尽管操作处理程序将位于该边界之外。

CQS on Wikipedia

这是一个老问题,但我打算尝试回答一下。我不经常在 Whosebug 上回答问题,所以如果我在链接到事物、写长答案等方面做了超出社区范围的事情,请原谅我。

CQRS 和 CQS 之间存在许多差异,但是 CQRS 在其定义中使用 CQS!让我们从定义两者开始,然后我们可以讨论差异。

CQS 根据它们的 return 值定义了两种类型的消息:没有 return 值(void)指定这是一个命令; return 值(非空)指定此方法是一个查询。

  • 命令更改信息
  • 查询return信息

命令改变状态。查询没有。

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

总体思路很简单; 之后的所有事情都会变得有趣。网上有很多讨论,其中我讨论了一些相关的属性(抱歉,这里输入的太多了!)。