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

2019 年 7 月 29 日 CSDN

作者 | 倪升武

责编 | 郭   芮

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


CRUD系统


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

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

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

这时候,CQRS 就该登场了。


CQRS系统


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

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

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


CQRS 实现方式


CQRS 可以有两种实现方式。

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

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


CQRS 的简单实现


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

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

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

public interface Command<T{
    Object execute(T commandModel);
}

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

@Component
public class CreateOrderCommand implements Command<CreateOrderModel{

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

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

@Component
public class CommandBus {
    public <T> Object dispatch(Command<T> cmd, T model) {
        return cmd.excute(model);
    }
}

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

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

@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,实际中运用是非常广泛的。


总结


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

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

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

作者简介:倪升武,CSDN 博客专家,CSDN达人课作者。硕士毕业于同济大学,曾先后就职于 eBay、爱奇艺、华为。目前在科大讯飞从事Java领域的软件开发,他的世界不仅只有coding。

声明:本文为作者投稿,版权归其个人所有。

【END】

 热 文 推 荐 

三次创业,三次跨界,这次凭十万行核心C代码登上 GitHub Top 1!

苹果 Siri 被曝涉嫌泄露用户隐私;中国联通回应 5G 入网问题;PHP 7.4 beta 1 发布 | 极客头条

我与“顶级工程师”距离有多远?

☞Android 告急!

☞3个核心差异, 告诉你为什么Libra永远成不了比特币!

☞微博宕机复盘:什么样的技术架构,可支持80个明星并发出轨?

☞公开课 | 详解事件抽取与事件图谱构建

☞超酷炫!Facebook用深度学习和弱监督学习绘制全球精准道路图

☞中国第一程序员,微软得不到他就要毁了他!

点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

你点的每个“在看”,我都认真当成了喜欢
登录查看更多
1

相关内容

2015年,由IEEE可靠性协会主办的SERE会议(IEEE国际软件安全与可靠性会议)和QSIC会议(IEEE国际质量软件会议)合并为一个会议Q R S,Q代表质量,R代表可靠性,S代表安全性。本次会议为来自工业界和学术界的工程师和科学家提供了一个平台,展示他们正在进行的工作,介绍他们的研究成果和经验,并讨论开发可靠、安全和可信系统的最佳和最有效的技术。它也为学术界提供了一个极好的机会,使他们能够在实践者将他们的需求摆在桌面上时,更加了解对软件行业至关重要的主题领域。第20届QRS会议将于2020年7月27日至31日在立陶宛维尔纽斯举行。官网链接:https://qrs20.techconf.org/
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
【干货书】现代数据平台架构,636页pdf
专知会员服务
253+阅读 · 2020年6月15日
斯坦福2020硬课《分布式算法与优化》
专知会员服务
118+阅读 · 2020年5月6日
《代码整洁之道》:5大基本要点
专知会员服务
49+阅读 · 2020年3月3日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
【数据中台】什么是数据中台?
产业智能官
17+阅读 · 2019年7月30日
每个架构师都应该培养业务思维
InfoQ
3+阅读 · 2019年4月21日
亿级订单数据的访问与存储,怎么实现与优化?
码农翻身
16+阅读 · 2019年4月17日
年薪48万的程序员,他究竟做对了什么?
机器学习算法与Python学习
7+阅读 · 2018年12月28日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
可能是讲分布式系统最到位的一篇文章
InfoQ
8+阅读 · 2018年11月19日
Flink 靠什么征服饿了么工程师?
阿里技术
6+阅读 · 2018年8月13日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
【区块链】区块链是什么?20问:读懂区块链
产业智能官
8+阅读 · 2018年1月10日
dynnode2vec: Scalable Dynamic Network Embedding
Arxiv
14+阅读 · 2018年12月6日
Relational recurrent neural networks
Arxiv
8+阅读 · 2018年6月28日
Bidirectional Attention for SQL Generation
Arxiv
4+阅读 · 2018年6月21日
Arxiv
13+阅读 · 2018年4月6日
VIP会员
相关VIP内容
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
【干货书】现代数据平台架构,636页pdf
专知会员服务
253+阅读 · 2020年6月15日
斯坦福2020硬课《分布式算法与优化》
专知会员服务
118+阅读 · 2020年5月6日
《代码整洁之道》:5大基本要点
专知会员服务
49+阅读 · 2020年3月3日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
相关资讯
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
【数据中台】什么是数据中台?
产业智能官
17+阅读 · 2019年7月30日
每个架构师都应该培养业务思维
InfoQ
3+阅读 · 2019年4月21日
亿级订单数据的访问与存储,怎么实现与优化?
码农翻身
16+阅读 · 2019年4月17日
年薪48万的程序员,他究竟做对了什么?
机器学习算法与Python学习
7+阅读 · 2018年12月28日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
可能是讲分布式系统最到位的一篇文章
InfoQ
8+阅读 · 2018年11月19日
Flink 靠什么征服饿了么工程师?
阿里技术
6+阅读 · 2018年8月13日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
【区块链】区块链是什么?20问:读懂区块链
产业智能官
8+阅读 · 2018年1月10日
Top
微信扫码咨询专知VIP会员