cqrs_命令和查询责任隔离(CQRS)模式

cqrs

The Command and Query Responsibility Segregation (CQRS) it’s an architectural pattern where the main focus is to separate the way of reading and writing data. This pattern uses two separate models:

命令和查询责任隔离(CQRS)是一种体系结构模式,其主要重点是分离读写数据的方式。 此模式使用两个单独的模型:

  • Queries — Which are responsible for reading data

    查询 -负责读取数据的查询

  • Commands — Which are responsible for update data

    命令 -负责更新数据

The Command and Query Responsibility Segregation (CQRS) pattern separates read and update operations for a data store. Implementing CQRS in your application can maximize its performance, scalability, and security.

命令和查询责任隔离(CQRS)模式将数据存储的读取和更新操作分开。 在您的应用程序中实现CQRS可以最大化其性能,可伸缩性和安全性。

The image below illustrates a basic implementation of the CQRS Pattern:

下图说明了CQRS模式的基本实现:

Commands

指令

Commands represent the intention of changing the state of an entity. They execute operations like Insert, Update, Delete. Commands objects alter state and do not return data.

命令表示更改实体状态的意图。 它们执行诸如插入,更新,删除之类的操作。 命令对象改变状态并且不返回数据。

Commands represent a business operation and are always in the imperative tense, because they are always telling the application server to do something. A command is an object with a name of an operation and the data required to perform the operation. For example:

命令代表业务操作,并且始终处于命令式时态,因为它们始终告诉应用程序服务器执行某项操作。 命令是具有操作名称和执行该操作所需的数据的对象。 例如:

public class DeactivateProductCommand : ICommand
{
public readonly int InventoryItemId
public redonly strnig Comment; public DeactivateProductCommand(int id, string comment)
{
IventoryItemId = id;
Comment = comment;
}
}

The commands are interpreted by the CommandHandlers and they return an event, which can be a successful event or a failure event. If the command succeed it will create a success event, and if the command fails it will create a failure event.

命令由CommandHandlers解释,它们返回一个事件,可以是成功事件或失败事件。 如果命令成功,它将创建成功事件,如果命令失败,则将创建失败事件。

Queries

查询

Queries are used to get data from the database. Queries objects only return data and do not make any changes.

查询用于从数据库获取数据。 查询对象仅返回数据,不做任何更改。

Queries will only contain the methods for getting data. They are used to read the data in the database to return the DTOs to the client, which will be displayed in the user interface.

查询将仅包含获取数据的方法。 它们用于读取数据库中的数据以将DTO返回给客户端,该DTO将显示在用户界面中。

Queries usually start with the word Get, because queries ask for the application to provide some data, for example:

查询通常以Get一词开头,因为查询要求应用程序提供一些数据,例如:

public class GetProductByIdQuery() : IQuery
{
public int Id { get; set; } public GetProductByIdQuery(int id)
{
Id = id;
}
}

Separated Databases

分离的数据库

When working with CQRS, it’s also possible — but it’s not mandatory — to have separate databases: a database only for reading the data, and a database only for making changes.

使用CQRS时,也可以(但不是强制性)拥有单独的数据库:仅用于读取数据的数据库和仅用于更改的数据库。

In traditional architectures, the same data model is used to query and update a database, and this is great for basic CRUD operations (remember of the KISS principle — if you want to read more about it, click here), but when we deal with more complex applications like microservices or any kind of application that has a high demand for data consumption, the common approach can become unwieldy, because having much writing and reading in the same database can affect the performance of the application (read and write workloads have very different performance and scale requirements). In this scenario you can use a database only for reading — and you can replicate this database to have more performance — and a database just for writing, where everything that will be writing in this database will be replied to the reading database.

在传统体系结构中,相同的数据模型用于查询和更新数据库,这对于基本的CRUD操作非常有用(请记住KISS原理,如果您想了解更多信息,请单击此处 ),但是当我们处理在诸如微服务之类的更复杂的应用程序或对数据消耗有很高要求的任何类型的应用程序中,通用方法可能变得笨拙,因为在同一个数据库中进行大量的读写会影响应用程序的性能(读写工作负载非常不同的性能和规模要求)。 在这种情况下,您只能将数据库用于读取(可以复制该数据库以提高性能),而数据库只能用于写入,在该数据库中将要写入的所有内容都将被复制到读取数据库。

The queries are used to execute the reading operations in the reading database and the commands are used to execute the change operations in the database that is used for update. In this case, it’s necessary to keep those databases in sync, one way of doing this is thought the use of events. Always when the command is called and change something in the writing database, a process needs to be called to updated the modified data in the reading database.

查询用于在读取数据库中执行读取操作,命令用于在数据库中执行用于更新的更改操作。 在这种情况下,有必要使这些数据库保持同步,一种实现方式是使用事件。 总是在调用命令并更改写入数据库中的某些内容时,才需要调用一个过程来更新读取数据库中的已修改数据。

It’s also possible to work with messaging together with CQRS, in this case the commands will go to a queue and the domain can read and handle with those commands.

还可以将消息传递与CQRS一起使用,在这种情况下,命令将进入队列,并且域可以使用这些命令进行读取和处理。

The image below illustrates the CQRS Patter using a database for reading and a database for update:

下图说明了使用数据库进行读取和数据库进行更新的CQRS模式:

When the CQRS can be used?

什么时候可以使用CQRS?

CQRS can be considered to be used on scenarios where:

CQRS可以被认为用于以下情况:

  • Has a high demand for data consumption

    对数据消耗有很高的要求
  • Performance of data reads must be tuned separately from the performance of data writes, especially when the number of reads is much greater than the number of writes.

    数据读取的性能必须与数据写入的性能分开调整,尤其是当读取次数远大于写入次数时。
  • There is the need for one team focus on the complex domain model that is part of the write model, while another team can focus on the read model and the user interfaces

    需要一个团队专注于作为写模型一部分的复杂域模型,而另一个团队可以专注于读模型和用户界面。
  • The system is expected to evolve over time and might contain multiple versions of the model, or where business rules change regularly.

    该系统预计会随着时间的推移而发展,并且可能包含该模型的多个版本,或者其中业务规则会定期更改。
  • Integration with other systems, especially in combination with event sourcing, where the temporal failure of one subsystem shouldn’t affect the availability of the others.

    与其他系统的集成,特别是与事件源的结合,其中一个子系统的时间故障不应影响其他子系统的可用性。

When the CQRS should not be used?

什么时候不应该使用CQRS?

CQRS is not recommended on scenarios where:

不建议在以下情况下使用CQRS:

  • The domain or the business rules are simple (remember of the KISS principle).

    域或业务规则很简单(请记住KISS原则)。
  • A simple CRUD-style user interface and data access operations are sufficient.

    一个简单的CRUD风格的用户界面和数据访问操作就足够了。

Benefits of CQRS

CQRS的好处

Like we saw before, CQRS can be very handy for some scenarios, and those are some benefits of CQRS:

就像我们之前看到的,CQRS在某些情况下非常方便,并且这些是CQRS的一些优点:

  • With the separation of concerns, helps to minimize and manage the complexity, making the application more maintainable, extensible, and flexible.

    通过关注点的分离,有助于最小化和管理复杂性,使应用程序更具可维护性,可扩展性和灵活性。
  • Segregating the responsibility between commands and queries can help to improve performance, scalability, and security.

    将命令和查询之间的责任分开可以帮助提高性能,可伸缩性和安全性。
  • The workloads between read and write operation will be different and using CQRS allows you to scale each of them independently of the others.

    读写操作之间的工作负载将有所不同,并且使用CQRS可使您独立于其他扩展它们。
  • Security is improved because you will have a single object model to execute an update operation ensuring that only the right classes will do it.

    安全性得到了改善,因为您将只有一个对象模型来执行更新操作,从而确保只有正确的类才能执行此操作。
  • Because each class is responsible for reads or writes, this reduces the chance of exposing data that should not available to a particular user.

    因为每个类都负责读取或写入,所以这减少了暴露特定用户不可用的数据的机会。

Disadvantages of CQRS

CQRS的缺点

Implementing CQRS also have some disadvantages that must be taken into account:

实施CQRS还具有一些必须考虑的缺点:

  • Increase the complexity of the code.

    增加代码的复杂性。
  • If using messaging to process commands and publish update events, the application must handle message failures or duplicate messages.

    如果使用消息传递来处理命令并发布更新事件,则应用程序必须处理消息失败或重复消息。
  • If you separate the read and write databases, the read database may be stale, and it can be difficult to detect when a user has issued a request based on stale read data. Even if you use event-sourcing or some other mechanism to keep the databases sync, there will be some time delay (even if it’s a small one) before the writing database be consistent. So you should consider that maybe you can be reading data that is stale.

    如果您将读取和写入数据库分开,则读取的数据库可能是过时的,并且可能难以检测用户何时基于过时的读取数据发出了请求。 即使您使用事件源或其他某种机制来保持数据库同步,在写入数据库之前,也会有一些时间延迟(即使很小)。 因此,您应考虑可能正在读取过时的数据。

Event Sourcing

活动采购

The CQRS pattern is often used together with the Event Sourcing Pattern (they work very well together). This pattern will be explained with more details in another article, but just to give a brief introduction, with this pattern the application state is stored as a sequence of events, and each event represents a set of changes to the data. This pattern allows us to keep all the states of an entity since it’s creation. With Event Sourcing, we can have not only the history of all changes but also the sequence in which those changes were made in an entity.

CQRS模式通常与事件源模式一起使用(它们可以很好地协同工作)。 在另一篇文章中将对此模式进行更详细的说明,但是仅作简要介绍,使用这种模式,应用程序状态存储为一系列事件,每个事件代表一组数据更改。 自创建实体以来,这种模式使我们能够保留其所有状态。 借助事件搜索,我们不仅可以了解所有变更的历史记录,还可以了解在实体中进行这些变更的顺序。

Event Sourcing ensures that all changes to application state are stored as a sequence of events. Not just can we query these events, we can also use the event log to reconstruct past states, and as a foundation to automatically adjust the state to cope with retroactive changes. — Martin Fowler

事件源确保将对应用程序状态的所有更改存储为一系列事件。 我们不仅可以查询这些事件,还可以使用事件日志来重构过去的状态,并作为自动调整状态以应对追溯性变化的基础。 —马丁·福勒(Martin Fowler)

For example, let’s suppose that you have a Product entity with a property “Name”, and on this property, you have the value “Table”. If you change the value for the property name from “Table” to “Chair”, when you get the data from this entity you will just have the new information. But when we work with Event Source, it’s possible to see the older values, because then we have a history of all changes that were made in the entity.

例如,假设您有一个具有属性“名称”的Product实体,并且在此属性上,您具有值“ Table”。 如果将属性名称的值从“ Table”更改为“ Chair”,那么当您从该实体获取数据时,您将只拥有新信息。 但是,当我们使用Event Source时,可能会看到较旧的值,因为这样我们便拥有该实体中所有更改的历史记录。

The CQRS pattern does not demand that Event Sourcing must be implemented, nether the Event Sourcing demand that the CQRS must be implemented, you can work with those patterns together or separately.

CQRS模式不要求必须实施事件源,鉴于必须实现CQRS的事件源需求,您可以一起或单独使用这些模式。

Although the CQRS can be used without events, they do complement each other so its common for systems that use CQRS to leverage the use of events. Events are one way to effectively communicate state changes so that the query model can stay up to date as the command model updates data.

尽管可以在没有事件的情况下使用CQRS,但它们确实可以互补,因此对于使用CQRS来利用事件的使用的系统来说,这是常见的。 事件是有效传达状态变化的一种方法,因此查询模型可以在命令模型更新数据时保持最新状态。

Conclusion

结论

The CQRS pattern can be very handy for more complex applications or application where we have a high demand for data consumption. For more commons scenarios where just basic operations will be executed, the CQRS can create unnecessary complexity to the application. So before deciding if you will implement CQRS or not, you always should consider what your application demands.

对于更复杂的应用程序或对数据消耗有很高要求的应用程序,CQRS模式可能非常方便。 对于仅执行基本操作的常见情况,CQRS可能会给应用程序带来不必要的复杂性。 因此,在决定是否实施CQRS之前,应始终考虑应用程序的要求。

Command and Query Responsibility Segregation (CQRS) pattern

命令和查询责任隔离(CQRS)模式

Software Architect’s Handbook — Joseph Ingeno

软件架构师手册— Joseph Ingeno

CQRS Documents by Greg Young

GQR Young的CQRS文件

Event Sourcing — Martin Fowler

活动采购—马丁·福勒

Code with Shadman — CQRS

Shadman的代码— CQRS

翻译自: https://medium.com/@henriquesd/the-command-and-query-responsibility-segregation-cqrs-pattern-16cb7704c809

cqrs

你可能感兴趣的:(java,数据库,python,mysql,linux)