CQRS and read models
Split the write shape from the read shape when one table cannot serve both well.
Open this lesson in the learning hubKey points
- CQRS is one idea: the model you write through does not have to be the model you read from.
- Writes stay normalised and validated. Reads get a flat table shaped exactly like the screen that asks for them.
- A read model is built by folding events, so it is disposable: drop it, replay the log, and it comes back identical.
- It is eventually consistent by construction. Right after a write, read back from the write side or the user misses their own change.
- Do not reach for it by default. Use it where read and write loads genuinely differ, never on ordinary CRUD.
Example
import java.util.List;
/** The write side is a log of facts. The read side is a fold of that log. */
public class Main {
record Event(String orderId, String type, long cents) {}
// One flat row, shaped for the dashboard rather than for correctness.
static final class Summary {
int liveOrders;
long totalCents;
}
public static void main(String[] args) {
List<Event> log = List.of(
new Event("o-1", "OrderPlaced", 4999),
new Event("o-2", "OrderPlaced", 1500),
new Event("o-1", "OrderCancelled", 4999),
new Event("o-3", "OrderPlaced", 2500));
Summary view = project(log);
System.out.println("live orders : " + view.liveOrders);
System.out.println("total cents : " + view.totalCents);
// Read models are disposable: throw it away and rebuild from the log.
Summary rebuilt = project(log);
System.out.println("rebuild matches: "
+ (rebuilt.totalCents == view.totalCents
&& rebuilt.liveOrders == view.liveOrders));
}
static Summary project(List<Event> log) {
Summary s = new Summary();
for (Event e : log) {
switch (e.type()) {
case "OrderPlaced" -> { s.liveOrders++; s.totalCents += e.cents(); }
case "OrderCancelled" -> { s.liveOrders--; s.totalCents -= e.cents(); }
default -> { }
}
}
return s;
}
}
Shape the read side around the question being asked, and rebuild it from the log.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Microservices course, and every lesson in it is listed on the Microservices contents page.