A good CQRS framework Revenochszs, not allowed to reprint without the Bo master. Permitted reprint should be marked by the Author and blog homepage: Http://blog.csdn.net/chszs, Reveno Introduction
CQRS says command query Responsibility segregation, the separation of commands and query responsibilities, is an architectural pattern proposed by Greg Young to separate the system's read (query) and write (command) operations into two separate subsystems. This separation is valuable in some scenarios, but it is important to note that CQRS makes the system more complex for most systems.
Most transactional solutions now experience the pain of overly complex architectures and hard-to-maintain infrastructures, not to mention the cost of overall maintenance.
Reveno is an event-traceable transaction framework that provides a high-performance, low-latency, fault-tolerant, extremely simple, and JVM-based framework for transaction processing. The goal of Reveno is to provide an easy-to-use, domain-oriented development tool, transparent architecture, and a well-suited component that maximizes performance. The Reveno can complete millions transactions per second and delay at subtle levels.
The following is an example of an artificial banking system that traverses the entire development of the Reveno framework, describing the entire process of defining a Command object to performing transactional and inspection results.
Second, define the transaction processing model
In Reveno, there are two ways to define a model--mutable or immutable. In the following example, we use the default mode-immutable model. First, we should define an account entity, which represents a bank client:
public static class Account { public final String name; public final long balance; public Account add(long amount) { return new Account(name, balance + amount); } public Account(String name, long initialBalance) { this.name = name; this.balance = initialBalance; }}
Since the Reveno framework uses the CQRS model, we need to define a view for the account domain class, which can be used to query the model:
public static class AccountView { public final long id; public final String name; public final long balance; public AccountView(long id, String name, long balance) { this.id = id; this.name = name; this.balance = balance; }}
Iii. commands and transaction processing operations
To perform any transaction, you need to execute the command. The command dispatches the specified transaction execution according to some internal business logic, which implements the actual state mutation. The example simplifies some of the content. Reveno has a specific DSL syntax that is useful for simple cases, especially when a command handle executes a single transaction. If there is a high demand for latency and throughput, it is recommended to use the basic API.
First, we define a new instance of the engine with file system storage.
Reveno reveno = new Engine("/tmp/reveno-sample");
Then define a view mapper from the transaction to the query model:
reveno.domain().viewMapper(Account.class, AccountView.class, (id,e,r) -> new AccountView(id, e.name, e.balance));
Now, create a new transaction handle that adds the new account to the system:
DynamicCommand createAccount = reveno.domain() .transaction("createAccount", (t, c) -> c.repo().store(t.id(), new Account(t.arg(), 0))) .uniqueIdFor(Account.class).command();
Tell me quickly what's going on. We created a CreateAccount command object and its handle, added a new account to the repository, and assigned a new ID (auto-generated) account ID to the new account accessed via T.id ().
We also need to define some transactions to handle the balance of the debit/credit account, and for the sake of simplicity, debit is represented by a negative number.
DynamicCommand changeBalance = reveno.domain() .transaction("changeBalance", (t, c) - > c.repo().remap(t.longArg(), Account.class, (id, a) -> a.add(t.intArg("inc"))) ) .command();
A changebalance command needs to pass two parameters: one is the account ID parameter and the other is the value parameter of the asset.
Iv. implementation of transaction processing
The first transaction to be performed is to create a new account. Before this, however, the engine must be started:
reveno.startup();long accountId = reveno.executeSync(createAccount, map("name", "John"));
When adding 10,000$ to an account, such as:
reveno.executeSync(changeBalance, map("id", accountId, "inc", 10_000));
Now, the transaction model has a single account entity, and the assets on the account are 10,000$. After that, you can access the query model and check that all transactions have changed accordingly:
Assert.assertNotNull(reveno.query().find(AccountView.class, accountId));Assert.assertEquals(reveno.query().find(AccountView.class, accountId).name, "John");Assert.assertEquals(reveno.query().find(AccountView.class, accountId).balance, 10_000);
V. Restoring the System State
In a typical transactional environment, every successful result in northern Europe must be saved to a physical storage device, with the best balance of durability and performance to minimize loss in emergencies and maximize system availability and responsiveness.
Reveno frame is still relatively young, but also relatively stable. Can login official website view: http://reveno.org/
An excellent CQRS framework Reveno