Jeden Skill in Manus ausführen
mit einem Klick
mit einem Klick
Jeden Skill in Manus mit einem Klick ausführen
Loslegen$pwd:
$ git log --oneline --stat
stars:43
forks:11
updated:25. Mai 2026 um 13:32
SKILL.md
| name | CQRS模式 |
| description | 命令查询责任分离,将数据的写入操作和读取操作分别用不同的模型处理,优化各自的性能。 |
CQRS 将系统分为命令端(写)和查询端(读),使用不同的模型处理各自的需求。
核心思想:
┌─────────────┐
命令 → │ 写模型 │ → 领域模型(充血、聚合、事务)
│ (Command) │ → 数据库(规范化)
└─────────────┘
│ 事件/同步
▼
┌─────────────┐
查询 → │ 读模型 │ → 查询优化的视图
│ (Query) │ → 数据库(反规范化)
└─────────────┘
// 命令端:严格的领域模型
public class OrderCommandHandler {
private final OrderRepository orderRepo;
public void handle(PlaceOrderCommand cmd) {
Order order = orderRepo.findById(cmd.getOrderId());
order.place(); // 领域逻辑
orderRepo.save(order);
// 发布事件 → 更新读模型
}
public void handle(CancelOrderCommand cmd) {
Order order = orderRepo.findById(cmd.getOrderId());
order.cancel(cmd.getReason());
orderRepo.save(order);
}
}
// 查询端:为展示优化的模型
public class OrderQueryService {
private final JdbcTemplate jdbc;
// 直接查询优化后的视图,不走领域模型
public OrderListDTO findOrders(OrderSearchCriteria criteria) {
String sql = "SELECT o.id, o.status, c.name as customer_name, "
+ "o.total_amount, o.created_at "
+ "FROM order_view o JOIN customer c ON o.customer_id = c.id "
+ "WHERE o.status = ? ORDER BY o.created_at DESC LIMIT ?";
return jdbc.query(sql, criteria.getStatus(), criteria.getLimit());
}
public OrderDetailDTO findOrderDetail(String orderId) {
// 从反规范化的视图中一次查出所有需要的数据
return jdbc.queryForObject(
"SELECT * FROM order_detail_view WHERE id = ?", orderId);
}
}
# 命令端
class PlaceOrderCommandHandler:
def __init__(self, order_repo, event_publisher):
self.order_repo = order_repo
self.event_publisher = event_publisher
def handle(self, cmd: PlaceOrderCommand):
order = self.order_repo.find_by_id(cmd.order_id)
order.place()
self.order_repo.save(order)
for event in order.collect_events():
self.event_publisher.publish(event)
# 查询端
class OrderQueryService:
def __init__(self, read_db):
self.read_db = read_db
def search_orders(self, filters: dict) -> list[OrderSummaryDTO]:
"""直接从读优化的视图查询"""
return self.read_db.query("order_summary_view", filters)
# 读模型更新器(监听事件)
class OrderReadModelUpdater:
def on_order_placed(self, event: OrderPlacedEvent):
self.read_db.upsert("order_summary_view", {
"id": event.order_id,
"status": "PLACED",
"customer_name": event.customer_name,
"total": event.total_amount,
})
✅ 适用场景:
- 读写比例悬殊(读多写少)
- 读和写的模型差异大
- 需要独立扩展读和写
- 需要复杂的查询(报表、搜索)
❌ 不适用场景:
- 简单的 CRUD 应用
- 读写模型几乎相同
- 团队不熟悉事件驱动
- 最终一致性不可接受
| 变体 | 说明 | 复杂度 |
|---|---|---|
| 同一数据库 | 写和读用同一个库的不同视图 | 低 |
| 独立数据库 | 写用关系数据库,读用 Elasticsearch/Redis | 中 |
| 事件溯源 + CQRS | 写端用事件,读端从事件投影 | 高 |
| 概念 | 关系 |
|---|---|
| 领域事件 | 事件驱动读模型更新 |
| 事件溯源 | 常与 CQRS 配合使用 |
| 读模型优化 | 读端的具体优化策略 |
| 聚合根 | 命令端使用聚合模型 |
核心:读写分离,各自优化。命令端用领域模型保证业务正确,查询端用反规范化视图保证性能。
权衡:增加了架构复杂度,换来了读写各自的可扩展性和性能。
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
在DDD中具有唯一身份标识和生命周期的对象,通过身份而非属性值相等判断。
封装复杂对象和聚合的创建过程,将创建职责从领域对象中剥离,保证聚合创建时的不变量满足。
没有身份标识,通过属性值判断相等的对象。不可变,通常代表领域中的度量或描述。
将DDD战略设计应用于微服务架构,限界上下文指导服务拆分,领域事件实现服务间通信。
对比 MVC 模式与 DDD 方法论的差异,分析 MVC 在复杂业务下的局限性,帮助团队判断何时应采用 DDD。