Loading [MathJax]/jax/output/CommonHTML/config.js
部署DeepSeek模型,进群交流最in玩法!
立即加群
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >程序员除了会CRUD之外,还应该知道什么叫CQRS!

程序员除了会CRUD之外,还应该知道什么叫CQRS!

作者头像
技术从心
发布于 2019-08-06 02:53:45
发布于 2019-08-06 02:53:45
50500
代码可运行
举报
文章被收录于专栏:技术从心技术从心
运行总次数:0
代码可运行
阅读本文约需要5分钟

今天主要跟大家分享一下什么是 CQRS,以及在项目中如何去使用。

1. CRUD系统

我们平常最熟悉的就是三层架构,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体。然后通过业务层来处理业务逻辑,将处理结果封装成DTO对象返回给控制层,再通过前端渲染。反之亦然。

这里基本上是围绕关系数据库构建而成的“创建、读取、更新、删除”系统(即CRUD系统),此类系统在一些业务逻辑简单的项目中可能没有什么问题,但是随着系统逻辑变得复杂,用户增多,这种设计就会出现一些性能问题。

我们经常用到的解决方案就是对数据库进行读写分离。让主数据库处理事务性的增、删、改操作,让从数据库处理查询操作,然后主从数据库之间进行同步。但是这只是从DB角度处理了读写分离,从业务或者系统层面上来说,读和写的逻辑仍然是存放在一起的,他们都是操作同一个实体对象。

这时候,CQRS 就该登场了。

2. CQRS系统

简单的说,CQRS(Command Query Responsibility Segration)就是一个系统,从架构上把 CRUD 系统拆分为两部分:命令(Command)处理和查询(Query)处理。其中命令处理包括增、删、改。

然后命令与查询两边可以用不同的架构实现,以实现CQ两端(即Command Side,简称C端;Query Side,简称Q端)的分别优化。两边所涉及到的实体对象也可以不同,从而继续演变成下面这样。

当然了,CQRS 作为一个读写分离思想的架构,在数据存储方面,也没有做过多的约束。所以 CQRS可以有不同层次的实现。

3. CQRS 实现方式

CQRS 可以有两种实现方式。

1)CQ 两端数据库共享,只是在上层代码上分离。这样做的好处是可以让我们的代码读写分离,更容易维护,而且不存在 CQ 两端的数据一致性问题,因为是共享一个数据库的。这种架构是非常实用的(也就是我上面画的那种)。

2)CQ 两端不仅代码分离,数据库也分离,然后Q端数据由C端同步过来。同步方式有两种:同步或异步,如果需要 CQ 两端的强一致性,则需要用同步;如果能接受 CQ 两端数据的最终一致性,则可以使用异步。C端可以采用Event Sourcing(简称ES)模式,所有C端的最新数据全部用 Domain Event 表达即可;而要查询显示用的数据,则从Q端的 ReadDB(关系型数据库)查询即可(详细可以参考文献3)。

4. CQRS 的简单实现

说了这么多,该怎么实现呢?我们以上面提到的第一种方式为例:代码层面实现分离,数据库共享。这种方式在企业里也非常实用。

首先有几个概念需要介绍一下,CQRS 模式中,首先需要有 Command,这个 Command 命令会对应一个实体和一个命令的执行类。那整个系统中肯定有很多不同的 Command,那么还需要一个 CommandBus 来做命令的分发处理。

可能大家觉得比较抽象,我来写几行示例代码,一看就明白了。假设有个订单模块,我要新增一个订单信息。那么根据上文的分析,需要有个新增命令以及对应的订单实体(并不一定和数据库的订单实体完全对应)。首先先创建一个命令接口(绑定命令对应的实体),接口内部有个该命令的处理方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Command<T> {
     Object execute(T commandModel);
}

OK,接下来我们可以创建订单的新增命令了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class CreateOrderCommand implements Command<CreateOrderModel> {

     @Override
     public Object execute(CreateOrderModel model) {
         // 具体的逻辑
    }
}

到这里,我们写好了具体的创建订单命令的逻辑,那么该命令需要放到 CommandBus 中去执行,所以我们要写这个 CommandBus。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
public class CommandBus {
     public <T> Object dispatch(Command<T> cmd, T model) {
         return cmd.excute(model);
    }
}

可能大家会看着有点晕,甚至有点绕,没关系,我解释一下:这个 dispatch 方法就相当于分发执行,内部根据传入的具体 Command 以及对应的 model,去执行该 Command 实现的逻辑。

好了,那我们在熟悉的 Controller 层该如何去调用呢?很简单,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
@RequestMapping(value = "/order")
public class OrderController {

     @Resource
     private GetOrderInfoService getOrderInfoService;
     @Resource
     private CreateOrderCommand createOrderCommand;
     @Resource
     private CommandBus commandBus;

     @PostMapping(value = "/getInfo")
     public Object getOrderInfo(GetOrderInfoModel model) {
         return getOrderInfoService.getOrderInfos(model);
    }

     @PostMapping(value = "/creat")
     public Object createOrderInfo(CreateOrderModel model) {
         return commandBus.dispatch(createOrderCommand, model);
    }
}

我还写了一个获取订单信息的接口,大家有没有发现,查询和插入是不同的方式,插入走的是 CommandBus 分发到 CreateOrderCommand 去执行,而查询则是直接走 service 层去查。这就是 CQRS 模式。

当然了,当命令越来越多的时候,也可以将 CommandBus 抽象出接口,可以根据业务需求,实现多个不同的 CommandBus 来分发命令。

除此之外,CQRS 还可以用在任务调度模块中,不同的任务可以包含不同的 Command,实际中运用是非常广泛的。

5. 总结

CQRS 是一种思想很简单清晰的设计模式,他通过在业务上分离操作和查询来使得系统具有更好的可扩展性及性能,使得能够对系统的不同部分进行扩展和优化。在 CQRS 中,所有的涉及到对 DB 的操作都是通过发送 Command,然后特定的 Command 触发对应事件来完成操作,也可以做成异步的,主要看业务上的需求了。

CQRS 虽然在思想上简单,但是实现上相对来说复杂些,也涉及到 DDD 的一些概念了,当然了,这篇文章主要是介绍以及演示 CQRS 模式的基本实践,更多知识需要大家再深入的去学习。

最后,希望阅读完本文,能对你有所帮助。

参考文献:

1.https://msdn.microsoft.com/magazine/mt703431

2.https://blog.csdn.net/rocketluoqq/article/details/81434871

3.https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589792(v=pandp.10)

4.https://www.cnblogs.com/yangecnu/p/Introduction-CQRS.html

每天

进步一点点

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术从心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从横切到纵切,架构模式CQRS,提高系统进化能力
曾几何时,你是否疑惑于VO、PO、DTO、BO、POJO、Entity、MODEL的区别?
Bug开发工程师
2020/02/10
9360
【愚公系列】2023年01月 .NET CORE工具案例-基于MediatR的CQRS模式
CQRS 是一种与领域驱动设计 (DDD) 和事件溯源相关的架构模式,本质上是一种读写逻辑分离的机制。
愚公搬代码
2023/03/16
6070
【愚公系列】2023年01月 .NET CORE工具案例-基于MediatR的CQRS模式
CQRS模式学习
当我们系统中的数据模型层级较少时,数据模型足够简单时,模型与数据库可以直接进行映射。这种简单数据模型使我们不需要针对其相互关系进行复杂的建模设计,直接在工程中使用经典的三层模型就足以支撑项目需求。
全栈程序员站长
2022/11/17
4730
CQRS模式学习
CQRS架构实战
2.什么是CQRS 这里只通过Udi Dahan的《Clarified CQRS》文章中的一张图片简要介绍一下:
IT云清
2021/12/06
7650
CQRS架构实战
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
图自https://time.geekbang.org/dailylesson/detail/100056986
王新栋
2022/06/15
3940
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
从单体架构迁移到 CQRS 后,我觉得 DDD 并不可怕
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/08/29
9270
从单体架构迁移到 CQRS 后,我觉得 DDD 并不可怕
CQRS 与 Event Sourcing:如何高效处理复杂业务场景!
这里先给大家推荐一篇实用的好文章:《从小改动到系统崩溃:一场“蝴蝶效应”般的Debug惊魂记!》 来自作者:bug菌
喵手
2024/12/01
1980
CQRS 与 Event Sourcing:如何高效处理复杂业务场景!
CQRS被称为邪教?
CQRS全称Command Query Responsibility Segregation
码农戏码
2022/06/07
8070
CQRS被称为邪教?
浅谈命令查询职责分离(CQRS)模式
在常用的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体。在一些业务逻辑简单的系统中可能没有什么问题,但是随着系统逻辑变得复杂,用户增多,这种设计就会出现一些性能问题。虽然在DB上可以做一些读写分离的设计,但在业务上如果在读写方面混合在一起的话,仍然会出现一些问题。 本文介绍了命令查询职责分离模式(Command Query Responsibility Segregation,CQRS),该模式从业务上分离修改 (Command,增,删,改,会对系统状态进行修改)和查
逸鹏
2018/04/11
2.2K0
浅谈命令查询职责分离(CQRS)模式
CQRS架构简介
http://www.cnblogs.com/netfocus/p/4055346.html
bear_fish
2018/09/19
1.6K0
CQRS架构简介
后端开发实践系列——领域驱动设计(DDD)编码实践
的确,很多时候软件的业务逻辑是无法通过推理而得到的,有时甚至是被臆想出来的。这样的结果使得原本已经很复杂的业务变得更加复杂而难以理解。而在具体编码实现时,除了应付业务上的复杂性,技术上的复杂性也不能忽略,比如我们要讲究技术上的分层,要遵循软件开发的基本原则,又比如要考虑到性能和安全等等。
ThoughtWorks
2019/08/01
1.3K0
后端开发实践系列——领域驱动设计(DDD)编码实践
详解 CQRS 架构模式
从一开始,软件系统就被用于各种用途,针对它们的需求也随着时间的推移而增长。需求的变更可能与业务逻辑、伸缩性或系统的其他方面有关。
深度学习与Python
2021/05/07
6780
详解 CQRS 架构模式
🔍CQRS 与 Event Sourcing:如何高效处理复杂业务场景
这里推荐一篇实用的文章:《功能上线后,系统崩了!我怎么把它救回来的?》,作者:【喵手】。
bug菌
2024/12/01
2250
🔍CQRS 与 Event Sourcing:如何高效处理复杂业务场景
从单体架构迁移到 CQRS架构
软件设计是一个不断发展演进的过程。每个大型系统都是从小微系统开始的。当现有的架构遇到问题而又无法解决时,系统就会开始演进。每一次演进都会伴随着一些技术上的选择。需要解决什么问题?需要付出什么样的代价?作为一名架构师或高级工程师,必须找到一种合理的演进方式,在开发进度、技术栈、团队水平等各方面都能满足条件,这样才能制定出可行的解决方案。
架构之家
2022/09/27
4760
从单体架构迁移到 CQRS架构
API 设计:CQRS(命令查询职责分离)
CQRS(Command Query Responsibility Segregation)指的是命令查询职责分离。这是一种我从 Greg Young 处听到的模式描述。它的核心思想很简单,就是你在更新和读取操作时使用不同的模型,这样的话,会给整个系统的设计带来深远的变革。
四火
2022/07/15
5660
API 设计:CQRS(命令查询职责分离)
命令和查询责任隔离(CQRS)模式
通过使用单独的接口将读取数据的操作与更新数据的操作隔离开来。这可以最大化性能、可伸缩性和安全性。通过更高的灵活性支持系统随时间的发展,并防止更新命令在域级别引起合并冲突。
35岁程序员那些事
2020/02/24
1.1K0
Redux从设计到源码
本文主要讲述这三方面内容: Redux 背后的设计思想 源码分析以及自定义中间件 开发中的最佳实践 Redux背后的设计思想 在讲设计思想前,先简单讲下Redux是什么?我们为什么要用Redux?
美团技术团队
2018/03/12
1.4K0
Redux从设计到源码
DDD-CQRS能解什么问题
CQRS(Command and Query Responsibility Segregation)是一种与传统的DDD实现不同的模式,将写与读区分开。CQRS适用于DDD的原因在于查询本身不应当影响领域建模
方丈的寺院
2019/08/05
1.1K0
DDD-CQRS能解什么问题
DDD实战之六:战略设计之技术决策
特别说明:我在写这篇的过程中,发现前面第四、五篇的上下文识别和关系映射中一些错误:将“确认订单付款”和“确认接龙付款”错误的合并为一个用例“确认购买并付款”(其实应该是包含子用例“创建付款订单”),并且相应的跨上下文用例中也遗漏了“确认接龙付款”。
张逸
2023/03/23
6480
DDD实战之六:战略设计之技术决策
CQRS框架:AxonFramework 之 Hello World
Command Query Responsibility Segregation,CQRS 这个架构好象最近博客园里讨论得比较多,有几篇园友的文章很有深度,推荐阅读: CQRS架构简介 浅谈命令查询职责分离(CQRS)模式 DDD CQRS架构和传统架构的优缺点比较 比较有趣的是,以往一断谈及架构思路、OO这些,往往都是java大佬们的专长,而CQRS这个话题,好象.NET占了上风。园友汤雪华的ENODE开源大作,在github上人气也很旺。 于是,我逆向思路搜索了下java的类似项目,果然有一个Axon
菩提树下的杨过
2018/01/18
1.8K0
CQRS框架:AxonFramework 之 Hello World
相关推荐
从横切到纵切,架构模式CQRS,提高系统进化能力
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验