CQRS架构窥探

CQRS模式,即命令查询责任分离,将数据的读写操作分离,优化读写模型,解决复杂数据显示问题。本文深入解析CQRS的工作原理,探讨其在电商商品系统中的应用案例,以及如何提升代码质量和系统性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CQRS简介

命令查询的责任分离Command Query Responsibility Segregation (简称CQRS) 模式是一种架构体系模式,能够使改变模型状态和查询模型状态的动作实现分离,简单理解就是读写分离。属于DDD应用领域的一个模式。提到读写分离,我们都会用到数据库的读写分离,如MySQL数据库的主备,写主,读备,主备数据的同步由MySQL数据库底层帮我们完成。CQRS在理念上与数据库读写分离有相似之处,但二者的目的完全不同,数据库读写分离的目的是容灾、分摊压力、提升性能,CQRS旨在分离读写模型,解决数据显示的复杂性问题。在DDD的应用场景中,从资源库(Repository)中查询所有需要显示的数据是困难的,特别是在需要显示来自不同聚合类型与实例的数据时,领域越复杂,这种查询困难程度越大。

命令与查询分离

Bertrand Meyer在1988年出版的《面向对象软件架构》一书中提出了“命令查询分离”的概念,Meyer说,原则上一个方法不应该既修改数据又返回数据,所以我们就有了两类方法:

  1. 查询:返回数据,但不修改数据,所以不会产生副作用;
  2. 命令:修改数据,但不返回数据。这与SOLID中的单一职责(Single Resposibility Principle)一脉相承。

不过,仍然会有一些模式逃逸于这个原则之外。比如,正如Martin Flowler所说的,从一个队列或栈弹出一个元素时,不仅改变了这个队列或栈,还返回了一个元素。

CQRS处理流程

在这里插入图片描述
将数据CRUD的CUD(新增、修改、删除)操作和R(查询)进行分离,前者称为Command,走Command bus进入Domain对模型进行操作,而查询则从另外一条路径直接查询底层数据存储,比如报表输出、数据检索等,发挥SQL、搜索引擎、缓存等底层数据存储的优点。

具体要怎么做呢?针对同一个模型,我们将那些纯粹的查询功能从命令功能中分离出来。聚和将不再有查询方法,而只有命令方法。资源库也将变成只有add()或save()方法(分别支持创建和更新操作),同时只有一个查询方法,比如fromId()。这个唯一的查询方法将聚和的身份标识作为参数,然后返回该聚合实例。资源库不能使用其他方法来查询聚和,比如对属性进行过滤等。在将所有查询方法移除后,我们将此时的模型称为命令模型(Command Model)。但是我们仍然需要向用户显示数据,为此我们将创建第二个模型,该模型专门用于优化查询,我们称之为查询模型(Query Model)。

sample

在电商系统中,商品是一个很重要的元素,商品也是一个非常复杂的体系,商品体系涉及到多级类目、卖家信息、前后台类目、各种属性、SPU、SKU等等,领域和展现形式都非常复杂。大部分的商品系统都会支持搜索功能,所以商品系统经常需要引入搜索引擎来支持搜索功能,这样由于存储结构的不同再加上领域和展现形式的复杂性,导致商品展示的实现复杂度会非常高。页面的商品展示可能需要展示不同聚和类型的信息,这时我们不但要将数据对象转换成所需的领域实体,还需要根据页面需要的信息对领域实体信息进行整合和过滤,涉及到的领域实体越多,这个过程就会愈加的复杂。这时我们可以引入CQRS来解决这个问题:
在这里插入图片描述
首先我们将应用层服务拆分为命令服务和查询服务,将创建商品、删除商品等CUD操作走应用层命令服务进入领域层,完成对应的领域模型行为后,通过资源库将数据进行持久化然后发出领域事件,资源库的实现可以放在基础设施层,根据我们系统中选择的基础设施将数据写入存储系统,示例中我们选择的是关系型数据库。接下来我们对领域事件进行处理,将数据同步至搜索引擎,这里的实现方式有很多,例如MySQL我们可以监听它的binlog等等,实现方式我们不展开细谈,无论什么样的方式,都是对领域事件处理的一种变相实现。

对于商品的搜索功能,我们构建查询模型,查询模型可以根据数据的使用方式进行构建,也可以面向页面,总之无需受限于领域模型的结构,可以根据查询需求进行灵活的构建。搜索请求经过查询服务直接进入数据访问层,同样我们可以在基础设施层实现查询服务,解耦基础设施,搜索召回的数据对象直接转换成查询模型,无需经过领域层,这样不但能够简化查询逻辑,还能提升一定的性能。

总结

CQRS 让读模型和写模型完全分离,因此可以对读操作和写操作进行优化,这样会带来性能上的提升,同时也会让代码代码更清晰、更简单,代码反映了领域模型,提升了代码的可维护性。

这一切都是关于封装、低耦合、高内聚和SRP(单一职责原则)。

不过,尽管CQRS可以让应用程序变得更健壮,但并不是说所有的应用程序都要使用CQRS。如果用户界面并不过于复杂或者我们只是需要在单个视图中处理聚和,那么引入CQRS反而会增加额外的复杂性。我们应该在必要的时候选择正确的方案。

参考文献

  • 《架构师之路月刊》
  • 《实现领域驱动设计》
1.系统需求 2 2.需求分析 4 2.1功能设置 4 2.2模块划分 5 2.3识别参与者和用例 6 2.3.1 顾客Customer用例图 7 2.3.2 系统管理员用例 13 2.3 静态结构模型 16 2.3.1 类Customer 17 2.3.2类Goods 18 2.3.3类Order 19 2.3.4管理员 20 2.3.5标题title类 20 2.3.6二级标题类 21 2.3.7公共操作类 22 2.3.8类图 23 3.动态行为模式 23 3.1时序图 23 3.1.1顾客注册成为会员时序图 24 3.1.2顾客反馈信息时序图 25 3.1.3顾客浏览商品时序图 26 3.1.4顾客查询商品时序图 27 3.1.5顾客购买商品时序图 28 3.2.6管理员添加商品时序图 29 3.2.7管理员删除商品时序图 29 3.2.8管理员添加二级商品目录时序图 30 3.2.9管理员删除二级商品目录时序图 31 3.2.10管理员编辑促销产品时序图 31 3.2.11管理员编辑条款信息时序图 32 3.2.12管理员编辑购买流程时序图 33 3.2.13管理员删除会员时序图 34 3.2.14用户结算时序图 35 3.3.活动图 35 3.3.1用户顾客的活动图 35 3.3.2管理端管理员的活动图 36 3.4协作图 38 3.4.1顾客登录协作图 38 3.4.2顾客注册协作图 38 3.4.3顾客浏览商品协作图 39 3.4.4反馈信息协作图 39 3.4.5顾客查询商品协作图 40 3.4.6顾客购买商品协作图 40 3.4.7管理员删除会员协作图 41 3.4.8管理员添加商品协作图 41 3.4.9管理员添加商品标题协作图 42 3.4.10管理员删除商品协作图 42 3.4.11管理员删除标题协作图 43 3.4.12管理员编辑文本协作图 43 4.系统数据库设计 44 4.1数据库的需求分析 44 4.2数据库的逻辑设计 44 5.参考文献: 47
本项目示例基于spring boot 最新版本(2.1.9)实现,Spring Boot、Spring Cloud 学习示例,将持续更新…… 在基于Spring Boot、Spring Cloud 分布微服务开发过程中,根据实际项目环境,需要选择、集成符合项目需求的各种组件和积累各种解决方案。基于这样的背景下,我开源了本示例项目,方便大家快速上手Spring Boot、Spring Cloud 。 每个示例都带有详细的介绍文档、作者在使用过程中踩过的坑、解决方案及参考资料,方便快速上手为你提供学习捷径,少绕弯路,提高开发效率。 有需要写关于spring boot、spring cloud示例,可以给我提issue哦 ## 项目介绍 spring boot demo 是一个Spring Boot、Spring Cloud的项目示例,根据市场主流的后端技术,共集成了30+个demo,未来将持续更新。该项目包含helloworld(快速入门)、web(ssh项目快速搭建)、aop(切面编程)、data-redis(redis缓存)、quartz(集群任务实现)、shiro(权限管理)、oauth2(四种认证模式)、shign(接口参数防篡改重放)、encoder(用户密码设计)、actuator(服务监控)、cloud-config(配置中心)、cloud-gateway(服务网关)、email(邮件发送)、cloud-alibaba(微服务全家桶)等模块 ### 开发环境 - JDK1.8 + - Maven 3.5 + - IntelliJ IDEA ULTIMATE 2019.1 - MySql 5.7 + ### Spring Boot 模块 模块名称|主要内容 ---|--- helloworld|[spring mvc,Spring Boot项目创建,单元测试](https://github.com/smltq/spring-boot-demo/blob/master/helloworld/HELP.md) web|[ssh项目,spring mvc,过滤器,拦截器,监视器,thymeleaf,lombok,jquery,bootstrap,mysql](https://github.com/smltq/spring-boot-demo/blob/master/web/HELP.md) aop|[aop,正则,前置通知,后置通知,环绕通知](https://github.com/smltq/spring-boot-demo/blob/master/aop/HELP.md) data-redis|[lettuce,redis,session redis,YAML配置,连接池,对象存储](https://github.com/smltq/spring-boot-demo/blob/master/data-redis/HELP.md) quartz|[Spring Scheduler,Quartz,分布式调度,集群,mysql持久化等](https://github.com/smltq/spring-boot-demo/blob/master/quartz/HELP.md) shiro|[授权、认证、加解密、统一异常处理](https://github.com/smltq/spring-boot-demo/blob/master/shiro/HELP.md) sign|[防篡改、防重放、文档自动生成](https://github.com/smltq/spring-boot-demo/blob/master/sign/HELP.md) security|[授权、认证、加解密、mybatis plus使用](https://github.com/smltq/spring-boot-demo/blob/master/security/HELP.md) mybatis-plus-generator|[基于mybatisplus代码自动生成](https://github.com/smltq/spring-boot-demo/blob/master/mybatis-plus-generator) mybatis-plus-crud|[基于mybatisplus实现数据库增、册、改、查](https://github.com/smltq/spring-boot-demo/blob/master/mybatis-plus-crud) encoder|[主流加密算法介绍、用户加密算法推荐](https://github.com/smltq/spring-boot-demo/blob/master/encoder/HELP.md) actuator|[autuator介绍](https://github.com/smltq/spring-boot-demo/blob/master/actuator/README.md) admin|[可视化服务监控、使用](https://github.com/smltq/spring-boot-demo/blob/master/admin/README.md) security-oauth2-credentials|[oauth2实现密码模式、客户端模式](https://github.com/smltq/spring-boot-demo/blob/master/security-oauth2-credentials/README.md) security-oauth2-auth-code|[基于spring boot实现oauth2授权模式](https://github.com/smltq/spring-boot-demo/blob/master/security-oauth2-auth-code/README.md) mybatis-multi-datasource|[mybatis、数据库集群、读写分离、读库负载均衡](https://github.com/smltq/spring-boot-demo/blob/master/mybatis-multi-datasource) template-thymeleaf|[thymeleaf实现应用国际化示例](https://github.com/smltq/spring-boot-demo/blob/master/template-thymeleaf) mq-redis|[redis之mq实现,发布订阅模式](https://github.com/smltq/spring-boot-demo/blob/master/mq-redis) email|[email实现邮件发送](https://github.com/smltq/spring-boot-demo/blob/master/email) jGit|[java调用git命令、jgit使用等](https://github.com/smltq/spring-boot-demo/blob/master/jGit) webmagic|[webmagic实现某电影网站爬虫示例](https://github.com/smltq/spring-boot-demo/blob/master/webmagic) netty|[基于BIO、NIO等tcp服务器搭建介绍](https://github.com/smltq/spring-boot-demo/blob/master/netty) ### Spring Cloud 模块 模块名称|主要内容 ---|--- cloud-oauth2-auth-code|[基于spring cloud实现oath2授权模式](https://github.com/smltq/spring-boot-demo/blob/master/cloud-oauth2-auth-code) cloud-gateway|[API主流网关、gateway快速上手](https://github.com/smltq/spring-boot-demo/blob/master/cloud-gateway) cloud-config|[配置中心(服务端、客户端)示例](https://github.com/smltq/spring-boot-demo/blob/master/cloud-config) cloud-feign|[Eureka服务注册中心、负载均衡、声明式服务调用](https://github.com/smltq/spring-boot-demo/blob/master/cloud-feign) cloud-hystrix|[Hystrix服务容错、异常处理、注册中心示例](https://github.com/smltq/spring-boot-demo/blob/master/cloud-hystrix) cloud-zuul|[zuul服务网关、过滤器、路由转发、服务降级、负载均衡](https://github.com/smltq/spring-boot-demo/blob/master/cloud-zuul) cloud-alibaba|[nacos服务中心、配置中心、限流等使用(系列示例整理中...)](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba) #### Spring Cloud Alibaba 模块 模块名称|主要内容 ---|--- nacos|[Spring Cloud Alibaba(一)如何使用nacos服务注册和发现](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba/README1.md) config|[Spring Cloud Alibaba(二)配置中心多项目、多配置文件、分目录实现](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba/README2.md) Sentinel|[Spring Cloud Alibaba(三)Sentinel之熔断降级](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba/README3.md) Dubbo|[Spring Cloud Alibaba(四)Spring Cloud与Dubbo的融合](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba/README4.md) RocketMQ|[Spring Cloud Alibaba(五)RocketMQ 异步通信实现](https://github.com/smltq/spring-boot-demo/blob/master/cloud-alibaba/README5.md) ### 其它 模块名称|主要内容 ---|--- leetcode|[力扣题解目录](https://github.com/smltq/spring-boot-demo/blob/master/leetcode) ## Spring Boot 概述 Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。 Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只需要很少的Spring配置。 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Sprin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值