解析CQRS架构模式

news2024/9/22 7:35:18

在日常开发过程中,关于如何正确划分操作的边界和职责一直是我们需要考虑的一个核心问题。针对这个问题,业界也诞生了一些新的设计思想和开发模式,其中最具代表性的就是今天要介绍的CQRS。

CQRS的全称是Command Query Responsibility Segregation,也就是命令和查询职责分离。从CQRS的名称上,我们不难看出该模式用来划分不同类型的操作。基于CQRS,我们在设计和实现具体的数据处理时需要引入一套专门的开发流程和方法。让我们一起来按一下。

CQRS模式设计理念

CQRS模式的核心设计理念来自于一条设计原则,即单一职责原则。所谓单一职责原则,指的是一个技术组件只应该负责具体一项职责,而不应该有多个导致该组件发生状态变化的操作。作为面向对象五个基本原则之一,在日常开发过程中应用非常广泛。而CQRS模式则在单一职责的基础上,对数据操作的类型进行了更进一步的划分,从而确保了系统的性能和安全性。让我们一起来看一下。

数据操作的类型

在详细介绍CQRS模式之前,我们先来对数据操作过程做一个简单的总结。数据操作的基本表现就是增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete),也就是通常所说的CRUD。如果我们仔细分析CRUD,会发现其实可以把它进一步拆分为读和写两个部分,其中CRUD中的R代表读,而剩余的CUD则代表写。


在我们执行一个具体的数据操作是,如果该操作的结果是返回一个值,它就具有查询(Query)的性质,也就是读的性质;而如果一个操作的目的是要改变数据的状态,那么它就具有命令(Command)的性质,也就是写的性质。


在上图中,我们把数据操作对应了一个个具体的方法上。通常,一个方法可能是纯的命令操作或者是纯的查询操作,也可能是两者之间的混合体。如果一个方法没有返回值,那么它肯定是命令操作。而如果一个方法有返回值,那么取决于该方法是否改版了数据的状态,可以是查询操作,也可以是查询+命令操作。


这种把命令操作和查询操作分离开来、各司其职的模式就是CQRS模式。基于CQRS模式,开发人员通过命令操作来改变数据的状态,而通过查询操作来获取最新的数据。

CQRS模式给我们的启示就在于:当在设计一个方法时,应该严格按照命令操作或查询操作来区分方法的行为,而不推荐设计如上图中所展示的查询+命令型的数据操作方式。这样改变对象状态的方法就需要被设计成没有返回值,而查询方法则不应该改变数据的状态。


CQRS的优势

CQRS模式的优势的非常明显的,查询操作和命令操作的分离,带来的好处就是有助于系统性能。从CQRS的基本概念,我们可以看出它的设计思想实际上和读写分离类似。读写分离的一般做法是把涉及到数据修改的操作放在主库,而把数据查询操作放到从库。

显然,通过读写分离机制,数据库的访问效率得到了提升,而这点对于方法调用和执行过程同样适用。


除了读写分离之外,CQRS的一大特色是可以根据需要提供多个查询操作。因为数据模型本身是稳定而干净的,所以我们可以选择性地明确想要展示的数据部分,并自由的对它们进行组合,从而实现不同的查询操作。我们可以分别对这些查询操作的性能进行专门的优化。


另一方面,CQRS模式也能为系统带来安全性。就数据操作而言,查询操作不会影响数据的状态,所以没有安全风险。而命令操作则相反。因此,如果我们事先能够对系统中所有的查询操作和命令操作进行区分,那么就可以把安全性控制的重点工作放在命令操作上,确保数据模型的安全性。


在现实应用开发过程中,查询操作的数量一般都是远远高于命令操作的。所以,通过CQRS模式,我们就能确保安全工作更加聚焦,降低安全控制的成本,提高效率。

CQRS的组成结构

讨论完CQRS的基本操作和优势之后,我们来分析该架构模式的具体组成结构。下图展示了CQRS模式的一种表现形式。

 

在上图中,我们把来自用户界面的操作分成两个入口,一个入口对接应用程序的查询模型,而另一个入口对接命令模型。而查询模型和命令模型的背后都是保存在数据库中的业务数据。

如果采用这种结构,好处是可以在业务代码层面实现读写分离,更容易维护。同时,因为读写同一个数据库,所以不存在命令模型和查询模型两者之间存在数据不一致性问题,实现上也比较简单。

另一种CQRS模式的实现策略就是把数据库也进行拆分。

可以看到,这里我们把原来单个的数据库拆分成查询操作数据库和命令操作数据库,然后通过实现这两个数据库之间的数据一致性。实现数据一致的方式有两种,如果需要查询和命令操作对应数据的强一致性,那么就需要实现基于同步机制的强一致性。反之,我们可以使用基于异步消息的最终一致性

整合事件溯源和CQRS

CQRS模式通常可以作为一种独立的数据管理的有效手段,但也可以和其他架构模式进行整合。尤其是在领域驱动设计中,CQRS模式和事件溯源模式天然可以集成。我们已经在《10分钟带你彻底搞懂事件溯源架构模式》中详细介绍了事件溯源模式。这里,我们可以简单回顾事件溯源机制的两个核心问题,即

  1. 如何生成领域事件?
  2. 领域事件生成之后,如何获取领域对象的状态信息?

针对这两个问题,在实现过程中,事件溯源机制通常会和CQRS结合起来一起使用,其中命令操作用于生成领域事件,而查询操作则用来查询实体状态。

在这里,我们还是需要强调一点。CQRS和事件溯源之间其实并没有直接的关系。但命令和事件往往是成对出现的。所以,CQRS模式与领域事件结合之后可以构建高度低耦合系统。下图展示了整合CQRS和事件溯源之后的结构图。


基于上图,我们可以对CQRS和事件溯源的整合过程总结成四点:

  1. 把领域事件作为最核心的技术组件看待,围绕领域事件设计整个系统架构
  2. 使用专门的事件存储库来存储事件,而不是把它们保存在普通的持久化媒介中
  3. 使用命令服务更新实体状态并生成事件
  4. 通过查询服务提供实体状态的读取功能

在应用程序开发过程中,针对数据的操作可以分成“读”和“写”两大类。针对如何执行这两大类操作,我们可以引入今天介绍的CQRS模式。在CQRS模式中,通过严格区分命令操作和查询操作,开发人员可以高效而安全的对数据进行各种操作。而CQRS模式本身具备一定的架构体系,也可以和事件溯源机制进行整合,从而更好的应用到领域设计驱动中。在今天的内容中,我们也对这一主题进行了详细的讨论。在日常开发过程中,你可以按照今天介绍的内容进行尝试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1927457.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图——图的遍历(DFS与BFS)

前面的文章中我们学习了图的基本概念和存储结构,大家可以通过下面的链接学习: 图的定义和基本术语 图的类型定义和存储结构 这篇文章就来学习一下图的重要章节——图的遍历。 目录 一,图的遍历定义: 二,深度优先…

【java计算机毕设】网上购书管理系统MySQL servlet JSP项目设计源代码 期末寒暑假作业 小组作业

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】网上购书管理系统MySQL servlet JSP项目设计源代码 期末寒暑假作业 小组作业 2项目介绍 系统功能: servlet网上购书管理系统包括管理员、用户两种角色。 管理员功能包括订单管理(已…

前端Vue组件化实践:自定义加载组件的探索与应用

在前端开发领域,随着业务逻辑复杂度的提升和系统规模的不断扩大,传统的开发方式逐渐暴露出效率低下、维护困难等问题。为了解决这些挑战,组件化开发作为一种高效、灵活的开发模式,受到了越来越多开发者的青睐。本文将结合实践&…

MySQL下载安装使用教程图文教程(超详细)

「作者简介」:冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础著作 《网络安全自学教程》,适合基础薄弱的同学系统化的学习网络安全,用最短的时间掌握最核心的技术。 这一章节我们使…

Windows安装和使用Doccano标注工具

简介 开源链接:GitHub - doccano/doccano: Open source annotation tool for machine learning practitioners. Open source annotation tool for machine learning practitioners. Doccano是一款开源的文本标注工具,由人工智能公司Hironsan开发并在G…

uni app 本地打包apk 教程

前言: 各位同学大家好,最近帮别人打包了一个 uni 的项目编译成apk 所以觉得必要分享下。 上效果图 原始工程 这种uni 原始的工程我们直接 这样我们就可以运行到我们的模拟器或者真机上面去 手动打包 开发环境 Android Studio 下载地址:An

1讲8小时!张宇新36讲怎么学效果最大化?

别怕!解决以下问题,就能让学习效果最大化。 1. 理解有难度。 如果你习惯传统教学模式,例如武忠祥老师的强化课,可能会觉得张宇36讲信息量太大,难以在短时间内消化和理解。 这是因为,考研数学教学的一端&a…

一个审计人为什么要辞职去日本做码农??

今天翻阅报道的时候,看到一篇记者采访记录: 文章的题目是:“审计人辞职去日本做码农的心路历程”。由于标题吸引住了我,我就点进去了看看。 被采访的对象:她在国内审计行业工作两年多后,自学编程&#xf…

Cesium--获取当前相机中心与地面的射线焦点

本文记录获取当前相机中心与地面的射线焦点的方法,可用于视角缩放过程中,控制视角自动平滑切换到二维等场景: 方法一定是视角中心能与地面有交集,如果对着地平线或对着天空肯定是没效果的。直接放代码: //调整相机到正…

计算机志愿攻略,高考生的必读

高考结束 又一年高考结束了 1342万学子们寒窗苦读十二载 迈入考场的那一刻 既紧张又兴奋 即使过去很多年 我仍然能回忆起当年的情景 当高考结束的铃声响起 所有的紧张和压力仿佛瞬间释放 走出来的那一刻 不管结果如何 我们都为自己能够勇敢地走过这段旅程而感到骄傲 …

基于Three.js实现三维空间中的箭头移动动画

继上一篇文章中实现了三维管道的可视化和流动模拟,最近需要基于曲面做三维物体的移动动画效果,特别是箭头等指向性物体的移动,因此就编写了以下方案,主要实现了三维空间内箭头等物体的创建和指向调整及动画效果等,具体如下: 1.基于Thee.js实现箭头等物体创建-THREE.Arrow…

解读网传《深圳IT圈⭕新解读八小时工作制》

网传深圳IT圈的新解读八小时工作制 工作时间安排: 10:00-12:0014:00-18:0019:00-21:00 初看:有惊喜 上午开始时间晚:相对于传统的9点开始,这种安排允许员工有更多的早晨时间,可以用来休息或处理个人事务。下午和晚上分…

S7-200smart与C#通信

https://www.cnblogs.com/heizao/p/15797382.html C#与PLC通信开发之西门子s7-200 smart_c# s7-200smart通讯库-CSDN博客https://blog.csdn.net/weixin_44455060/article/details/109713121 C#上位机读写西门子S7-200SMART PLC变量 教程_哔哩哔哩_bilibilihttps://www.bilibili…

电脑关机被阻止

1. winR输入regedit进入注册表 2. 选择HKEY_USERS-》.DEFAULT-》Control Panel-》Desktop 3. 右键DeskTop新建字符串值,命名为AutoEndTasks,数值设置为1

香橙派AIpro部署YOLOv5:探索强悍开发板的高效目标检测能力

香橙派AIpro部署YOLOv5:探索强悍开发板的高效目标检测能力 一、香橙派AIpro开箱使用体验 1.1香橙派AIpro开箱 拿到板子后第一件事情就是开箱: 开箱后可以看见一个橘子的标识,也就是香橙派了,并且还有四个大字:为AI…

Ubuntu系统安装mysql之后进行远程连接

1.首先要配置数据库允许进行远程连接 1.1 打开MySQL配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf1.2 修改 bind-address 行 #按i进入插入模式 bind-address 0.0.0.0 #按 Esc 键退出插入模式。 #输入:wq 然后按 Enter 保存并退…

alike-cpp 编译

1. 源码链接: https://github.com/Shiaoming/ALIKE-cpp 2.已经安装好显卡驱动,cuda,cudnn,没安装的参考: 切记装cuda-11.x的版本,最好cuda11.3的版本 ubuntu重装系统后,安装cuda,cudnn-CSDN博客 3.安装…

UE5.4新功能 - MotionDesign上手简介

MotionDesign是UE中集成的运动图形功能,我们在游戏中经常会见到,例如前方漂浮于空中的若干碎石,当玩家走进时碎石自动吸附合并变成一条路,或者一些装饰性的物件做随机运动等等,在引擎没有集成运动图形时,这…

《0基础》学会Python——第九讲

函数 一、函数的定义: 指在程序中创建一个独立的代码块,用于完成特定的任务或执行特定的操作。函数通常接收输入参数,并返回输出结果。通过定义函数,可以将复杂的程序分解成更小的模块,提高代码的可读性和可维护性。 …

【密码学】密码学数学基础:群的定义

一、群的定义 在密码学中,群(Group)的概念是从抽象代数借用来的,它是一种数学结构,通常用于描述具有特定性质的运算集合。 群的定义 群定义中的几个关键要素: 集合:首先,群是由一系…