In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces "what is CQRS in DDD". In daily operation, I believe many people have doubts about what is CQRS in DDD. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the question of "what is CQRS in DDD?" Next, please follow the editor to study!
The beginning
With the continuous development of the business, the architecture of the software system is becoming more and more complex, but no matter how complex the business is finally implemented in the system, it is nothing more than read and write operations. Users write business data according to business rules, and then get the desired results according to query rules. Generally speaking, we will say that the read and write data is stored in a database and read and write to it through a set of models. In large systems, query operations are often much more than write operations, so there is the idea of read-write separation, which defines the model of read operation and write operation separately and provides different channels for users to use. CQRS (Command-Query Responsibility Segregation) is based on this idea to provide a mode of separation of reading and writing. Today, around it, we will tell you the following:
The Evolution and Architecture of CQRS
Principle and Application of Event Sourcing
The perfect combination of Event Sourcing and CQRS
The example of CQRS
The Evolution and Architecture of CQRS
CQRS (Command-Query Responsibility Segregation) is a mode of separation of reading and writing, literally understanding that Command is the meaning of command, which represents the write operation; Query is the meaning of query, which represents the query operation. The main idea of this mode is to separate the data writing operation from the query operation.
It originates from the principle of command query separation (CQS) designed by Bertrand Mayer. CQS declares that a class can only have two methods: methods that change the state and return void and methods that return the state. Greg Young is the person responsible for naming the pattern CQRS and promoting it.
First, let's take a look at how changes and queries in the system are handled before CQRS, as shown in figure 1:
Figure 1 traditional system request
The traditional system request starts with the leftmost Client and requests the system along the red line to the right through Application Service. Here Application Service can be understood as the facade of the system, or the Controller layer is responsible for receiving requests from the client. At this time, the content of the request is relatively simple and basically consistent with the information in the database, so DTO (Data Transfer Object) is used here to request directly. After passing through the Domain Model, DTO goes directly to Database and then returns to the client side along the blue line. The traditional request method uses the same data model, a set of Domain Model and the same database for partial read and write operations.
From the traditional operation point of view, the request of Client goes through Application Service, and the user's intention is all decomposed into CRUD operation, but it can not be reflected in Domain Model. In order to ensure the integrity and consistency of the DTO, the operation-independent information will be incorporated into the DTO, the query operation and creation operation share a DTO, and the business process of the domain model is weakened. In order to adapt to both query and creation operations, DTO is designed to be all-inclusive and bloated. As a result, there are unnecessary field transfers in the transmission.
Moreover, the conversion between DTO and domain objects is carried out many times in one operation, which increases the complexity of the system. In addition, the read and write operations will be carried out around the same data model, which is not the most efficient for the system with more read and write less, especially in the high concurrency system with read operation as the main operation.
Because of the above problems in the traditional system architecture, according to the different read and write responsibilities, CQRS divides the domain model into two parts: the command side and the Query side. As shown in figure 2, the red line part is the Command side, which corresponds to the Domain Model sending instructions for Command operation to write status information to the data.
The Query side, as a query operation, is represented by a blue line, obtains information from the database through Query Model, and returns the result to Client first through the black to the left. Both the Command side and the Query side enter the system through Application Service and share the same database, but the Command side only writes the state, and the query side only reads the status.
Figure 2 CQRS is divided into Command side and Query side
At present, the read and write operations have been separated, because the two operations still share a database, in order to improve the efficiency of reading and writing, the separation of the database has become an inevitable choice. As shown in figure 3, the original Database is separated into Writer Database and Reader Database for write and read operations, respectively. In order to ensure the data consistency of read and write operations, it is necessary to synchronize data between the two databases.
Because the data synchronization is timely, so the writer is the Command side and the reader is the Query side, so the system intelligently ensures the final consistency. So how do you ensure synchronization between the two libraries? Next we need to introduce the concept of Event Sourcing.
Principle and Application of Event Sourcing
Event Sourcing, also known as event traceability, is an architectural pattern proposed by Martin Fowler. The design idea is that the business in the system is completed by event-driven. Events are recorded in the system, and these events reflect the state of the information. Business data can be views generated by events and do not have to be saved to the database.
To make it easier to understand Event Sourcing, let's explain it further with an example, as shown in figure 3:
Fig. 3 Separation of read and write databases between Command and Query
We look from left to right. For a business class "account", owning "attributes" includes "account ID" and "account amount" information, while "methods" include "creating accounts", "depositing cash" and "withdrawing cash". The green event sequence in the middle is a series of actions for the "account", according to the serial number.
1. Create a bank account, assuming that the account ID at this time is "0001".
two。 Deposit 0001 yuan in cash for the "300" account.
3. Then withdraw 0001 yuan from the "100" account.
4. Finally, deposit another 200 yuan.
The series of events generated above will be saved to the event library in Event Store below, where the status information of the account will not be saved. When you need to obtain "account" data, through these event information, it will be restored to the final state of "account", that is, "account ID" is "0001" and "account amount" is 400. The specific implementation is to regenerate the current state through the corresponding processing methods of the four events related to the account. If each query status information needs to be handled in this way, it is bound to cause a waste of resources, so in the yellow section on the right, we will save the final "account" information through the view for query.
Figure 3 Event Sourcing example diagram
The above "account" processing process is Event Sourcing, which is, to put it bluntly, through the event handling mode. It records and saves all the operations in the system in the way of events, and the final state of any entity is confirmed by the superposition and restoration of events.
What Event Sourcing contains
The above introduces the implementation principle and basic concepts of Event Sourcing, here let's take a look at the main contents of it, so that we can have a more comprehensive understanding of it.
Aggregate object: in the example in figure 3, "account" is an aggregate object, which contains basic information such as "account ID" and "account amount", as well as methods for operating the account: "create an account", "deposit cash" and "withdraw cash". At the same time, "account" corresponds to a domain model in domain-driven development.
Event Store: in the Event Sourcing schema, the database where events are saved is called Event Store. You need to include the ID of the aggregate object in the event, as well as the order of the event. In this way, the relevant events can be found from the database according to the aggregate ID when querying, and the execution order can be restored by the sequence number of the events. That is, the reproduction of the event, that is, the event executed at a certain time is taken out, its handler function is called, and the business state at that point in time is restored.
In order to get the latest "account" status information, you need to get the corresponding events in Event Sourcing for playback, so as to get the current status, which will waste a lot of resources. So we will write the latest data state of the aggregate object into a table, which is the view. Or send this status information to other applications for subsequent business operations.
The content of the query is for the final state of the account, so the object should be the view. The setting here coincides with the separation of read and write in CQRS. The Event information of the Command side is stored through the Event Store, the information of the final state of the entity is stored through the view, and the Query side queries the data from the view back to the user.
Advantages and disadvantages of Event Sourcing
The above introduces the principle and content of Event Sourcing and then take a look at its advantages and disadvantages.
Advantages of Event Sourcing:
Traceability events and reproduction operations: especially in a complex business system, a transaction contains multiple operations, some of which are parallel and some serial. If you need to know the execution of the operation, you need to know each event like the back of your hand. Event Sourcing provides exactly the historical information of the event, making it easy to find out what happened at any point in time.
Tracking and repairing Bug: event analysis can be used to analyze the execution process of the business to help find the Bug, such as the sequence of events generated by the duplicate Bug, so as to locate the location of the Bug. After the Bug is found and repaired, the repair result can be verified by re-aggregating the business data and replaying the sequence of events executed, while the loss caused by Bug can be recovered.
Improve performance: in Event Sourcing mode, because it records the sequence of events, it is a new operation, and there is no update operation, so the performance of recording data is improved compared to the system that needs update operation. It also improves efficiency if you use views to pass the final state of the entity to other applications without having to write it to the database and read it later.
Disadvantages of Event Sourcing:
Change of thinking: the landing of Event Sourcing needs to be carried out in a domain-driven manner at design time and requires event-based responsive programming thinking. In this way, domain model design should be given priority rather than traditional database design priority.
Change the event structure: as the business process changes, you need to constantly adjust the event structure, add or modify some data to the event. This kind of behavior can affect "historical reproduction", and you need to consider the compatibility of previous event structures.
Deal with idempotent events: if the corresponding transaction is interrupted during execution, the final consistency of the transaction needs to be achieved by event playback. At this point, it is necessary to put forward requirements for the idempotency of the event, that is, the result of running the same event many times remains the same. Duplicate events need to be discarded during event processing.
Query event database (event store): because of the events stored in the database, it is relatively difficult to query the status of entities. These events need to be replayed to get the latest information about the state of the entity. This is why you need to separate reads and writes through CQRS, where the Command side uses Event Sourcing and the Query side uses Event Sourcing to issue the final state of the Event for query.
The perfect combination of CQRS and Event Sourcing
Through the introduction of Event Sourcing above, it can be found that the records for Event are stored in Event Store, and the final state is saved in the view can be supplied to query. This model naturally works well with CQRS.
From the structure of the CQRS schema, the change of the entity state occurs on the command side, and the Command side knows what specific operations the business process has done, and encapsulates these specific operations to form an Event.
On the query side, the query returns the current state of the entity. According to the "current state + change = new state", if you can get the "change" from the Command side, plus the "current state" obtained by the Query side itself, you can get the changed "new state".
At this time, the Event issued by the Command side coincides with this "change". If the Command side pushes the Event to the query side when the change occurs, that is, the new Event is generated, and the query side refreshes the status according to the Event, it can ensure that the entities at both ends are consistent and achieve the final consistency, as shown in figure 4:
Fig. 4 combination of Event Sourcing and CQRS
Add Event Handler to figure 3, that is, the blue part of the figure, which receives the Event information sent from Domain Model, that is, the latest entity modification information. This information is then stored in a Reader Database (which can also be understood as a view) so that the new Event information plus the current entity information is the latest entity information. However, after using this method, the Query side can still obtain data through Reader Database, which does not affect its original operation.
Back on the Command side, the corresponding Event of multiple operations is stored in Event Store and saved as a record of business tracking.
What is mentioned above is only a mode of system architecture, which can be improved and optimized according to the specific situation in practical application. As shown in figure 5, you can join the queue during the Event exchange between the Command side and the Query side to meet the needs of two sets of applications deployed in different processes.
Figure 5 Command side and Query side join the queue
An example of CQRS
The above talk about the perfect combination of CQRS and Event Sourcing, here through an example to further introduce its operation process. The background of this example is that the corresponding contact information (Contact) and address (Address) are saved for the user (User).
Command is used to establish (Create) users (User) and update (Update) users (User); Query is used to query the corresponding residential address (Address) and contact information (Contact) of users (User).
As shown in figure 4, the Client request application is divided into two upper lines, each represented by four colors. We explain the process performed on the Command side and the Query side according to different colors.
Fig. 4 combination of Event Sourcing and CQRS
Red left line: this is mainly for the create and update operations of User, populating the CreateUserCommand class and the UpdateUserCommand class as input parameters for the UserAggregate aggregation class, respectively. In UserAggregate, it is handled by two methods, handleCreateUserCommand and handleUpdateUserCommand, respectively, and finally saved to Write database through UserWriteRepository.
The green down line: the area connected to purple is UserProjection, which synchronizes Write database data into Read database.
The blue line to the right: Client initiates a Query request to build the request through the AddressByRegionQuery class and the ContactByTypeQuery class, passing it to the UserProjection class for processing, where the handle method processes the requests for the two types of parameters, respectively. Finally, the information in Read database is obtained through UserReadRepository.
Purple left line: when the information is obtained from Read database, it is returned to Client.
Figure 6 CQRS example diagram
After understanding the overall architecture, let's take a look at the class structure of the specific implementation.
As shown in figure 7, the User entity class includes the following fields, that is, the business entity we want to operate on. It includes the basic information of the user, and the specific information of the contact and address classes is not described here.
Figure 7 User entity class
The class information for Command is shown in figure 8, and its content is relatively simple. For CreateUserCommand, it is mainly used to create users, including UserID and FirstName as well as LastName.
Figure 8 CreateUserCommand class
As shown in figure 9, updates to the address and contact information have been added to UpdateUserCommand.
Figure 9 UpdateUserCommand class
With Command, let's take a look at the aggregation class UserAggregate. Since it includes the processing methods of Create and Update, here we introduce the handleCreateUserCommand method, that is, dealing with new user commands.
Here you will create a UserCreatedEvent object and save it to Write database through WriteRepository. That is, the Event store in ES, and the list of event will be returned.
Figure 10 handleCreateUserCommand class
After processing the Command, Event will be returned. When the Event is saved to the database, it will also be updated with the query side as the latest entity status. Here, the UserProjector class will be used to complete the mapping. As shown in figure 11, the project method is processed one by one for the events of UserID.
Figure 11 UserProjector class
After looking at the Command side and the synchronized Projector, let's take a look at the classes on the query side. As shown in figure 12, the AddressByRegionQuery class defines UserID and State information.
Figure 12 AddressByRegionQuery class
As shown in figure 13, ContactByTypeQuery defines the information for UserID and ContactType.
Figure 13 ContactByTypeQuery class
As shown in figure 14, the AddressByRegionQuery and ContactByTypeQuery mentioned above are passed as parameters to the handle method of the UserProjection class, and the corresponding Contact and Address information is returned. UserReadRepositiory is used to get data from Read database.
Figure 14 UserProjection
Finally, let's take a look at the test code, which is divided into seven steps, as shown in figure 15.
Randomly generate user ID.
Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community
Through CreateUserCommand, the Command of the newly created user is created, and the corresponding event is generated through UserAggregate.
Events are mapped to the database on the query side through UserProjector.
Through UpdateUserCommand, create a Command that updates the address information and generate the corresponding events.
Events are mapped to the database on the query side through UserProjector.
Through AddressByRegionQuery, create a Query that queries address information.
Execute the query to get the data from Read database and compare it with the hypothetical value.
Figure 15 implementation process of Command and Query
Finally, take a look at the directory structure of these files, as shown in figure 16.
Figure 16 file structure
At this point, the study of "what is the CQRS in DDD" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.