SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/microwind/ai-skills --skill cqrs명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
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,
: event.total_amount,
})
✅ 适用场景:
- 读写比例悬殊(读多写少)
- 读和写的模型差异大
- 需要独立扩展读和写
- 需要复杂的查询(报表、搜索)
❌ 不适用场景:
- 简单的 CRUD 应用
- 读写模型几乎相同
- 团队不熟悉事件驱动
- 最终一致性不可接受
| 变体 | 说明 | 复杂度 |
|---|---|---|
| 同一数据库 | 写和读用同一个库的不同视图 | 低 |
| 独立数据库 | 写用关系数据库,读用 Elasticsearch/Redis | 中 |
| 事件溯源 + CQRS | 写端用事件,读端从事件投影 | 高 |
| 概念 | 关系 |
|---|---|
| 领域事件 | 事件驱动读模型更新 |
| 事件溯源 | 常与 CQRS 配合使用 |
| 读模型优化 | 读端的具体优化策略 |
| 聚合根 | 命令端使用聚合模型 |
核心:读写分离,各自优化。命令端用领域模型保证业务正确,查询端用反规范化视图保证性能。
权衡:增加了架构复杂度,换来了读写各自的可扩展性和性能。