• 什么是CQRS?


    什么是CQRS

    CQRS 是一种与领域驱动设计 (DDD) 和事件溯源相关的架构模式。Greg Young 在 2010 年创造了这个术语,CQRS 的内容基于 Bertrand Meyer 的 CQS 设计模式。图片来源:《Clarified CQRS》
    在这里插入图片描述
    CQRS(Command Query Responsibility Segregation)架构模式。它也将写入和读取分开。它提出了单独的 API,一个专用于更改应用程序状态的命令路由,另一个专用于返回有关应用程序状态信息的查询路由。

    查询 (Query)

    上图中,可以看到Query不是通过DB来查询,而是通过一个专门用于查询的Cache,实际使用中根据实际情况进行调整,可以是DB,缓存,MQ或者搜索引擎等中间件或者数据库。

    命令 (Command)

    业务逻辑大部分都发生在写入的时候,例如用户购买商品提交订单时,我们要验证库存,用户信息订单数据是否有效等。如果从传统DDD的角度看,Command类似于Application Service,用户的命令(如提交订单)会以Command的形式得到执行,而Command中也不会带有业务逻辑,Command中做的事情基本上是:通过Repository得到相关的领域对象,调用某些领域服务(Domain Service)执行一些操作(业务逻辑都将保留在领域模型中),然后执行Commit或SaveChanges之类的方法提交改动,之后,相关的数据就会写入到Write DB中(图的DB,下文统称Write DB)。需要注意的是,UI上的查询都是查Read DB,而不是Write DB。

    领域模型 (Domain Model)

    这和Evans的DDD中说的领域模型没有太多区别,是“the heart of software”。

    领域事件 (Domain Event)

    领域事件占据的地位非常重要,不仅限于CQRS。相信会有一部分人曾和我一样碰到过这样的问题:

    Account实体(表示帐户)有个Balance属性(表示帐户余额),我们一般不会公开这个属性的setter,而是通过写一些IncreaseBalance(decimal amount)之类的方法来实现帐户余额的变动。

    这时问题就来了,我们想在帐户变动时添加一条AccountLog记录,但Log记录成千上万,我们不能直接通过ORM的一对多映射把AccountLog集合实现成Account的一个集合属性,那我们就需要在IncreaseBalance()中得到AccountLogRepository,这样才有办法插入AccountLog(从DDD的角度,AccountLog不是聚合根,所以不能有AccountLogRepository,但在性能影响严重的时候,也只好做些取舍了)。

    不管用了依赖注入还是什么的,总之,Account已经依赖上Repository了,这就让领域对象变得很不纯净,并且,假如我们以后不仅要记录log,还要短信通知用户呢?那要修改源代码吗?这也很不OCP。

    而领域事件正好可以解决这种问题:只要在IncreaseBalance()方法的末尾,触发一个领域事件,然后我们独立写一个EventHandler的类去实现log的添加(框架可以保证EventHandler可以和领域事件绑定到一起)。

    回到CQRS,因为Command将数据写到了Write DB中,而UI查询的是Read DB,那我们就需要用某种方式实现这两个数据库的同步,解决办法已经很明显了,写一堆的EventHandler类去监听领域事件。例如我们有一个更改产品价格的命令ChangePriceCommand,它执行后,一个叫做PriceChangedEvent会被触发,那我们只要写一个PirceChangedEventHandler的类,在这里面将Read DB中相关的价格信息更改到最新值即可实现同步(这里会涉及到Read DB中表结构改变的问题,后面再说)。

    结语

    CQRS有意思的地方还不只这些,还有常和CQRS一起讨论的Event Sourcing(事件溯源,下面简称ES)等。

  • 相关阅读:
    [附源码]计算机毕业设计springboot线上社区管理系统
    数据治理-数据建模和设计-PRISM设计原则
    微信自动化工具开发系列01_自动获取微信聊天信息(2022年7月可用)
    他用AI,抄袭了我的AI作品
    LinkedList与链表
    达梦更换正式授权dm.key
    44特征02—— 对角化: 3阶复矩阵的相似对角化、矩阵方幂的计算
    初识贝塞尔(bezier)曲线
    从指定 URL 读取图像并以 OpenCV 格式返回的函数(从指定 URL 读取图像并使其可由 OpenCV 处理。)
    JS中内存泄漏的几种情况
  • 原文地址:https://blog.csdn.net/fwj380891124/article/details/126084197