1. Repository模式架构总览:分层位置、核心职责与边界
1.1 分层位置与核心职责
Repository 模式处于应用服务层与数据访问层之间的“接口隔离带”。它不直接操作数据库连接或 ORM 会话,而是通过抽象接口定义业务所需的集合式数据操作。下图为 Repository 在经典分层架构中的锚定位置与组件协作关系:
1.2 与 DAO / Service 的边界差异
| 维度 | Service | Repository | DAO |
|---|---|---|---|
| 语义粒度 | 业务场景(下单、审批) | 聚合根集合操作 | 单表 CRUD |
| 依赖方向 | 依赖 Repository 接口 | 依赖 DAO / ORM | 无上层依赖 |
| 返回值类型 | 业务 DTO / VO | 领域 Entity / Aggregate | PO / 数据记录 |
| 事务范围 | 跨 Repository 事务 | 单聚合事务边界 | 单数据源事务 |
| 测试模式 | Mock Repository 接口 | Mock DAO 或使用内存实现 | 集成测试或嵌入式 DB |
1.3 典型数据流场景
以“查询用户订单列表”为例,展示完整的数据流向与控制流:
- Service 调用
orderRepository.findByUserId(userId); - RepositoryImpl 将
userId转换成 DAO 查询参数; - DAO 执行 SQL 并返回
List<OrderPO>; - RepositoryImpl 将
OrderPO组装为Order领域实体; - Service 获得
List<Order>执行后续业务规则。
关键原则:Repository 不暴露 DAO/ORM 内部异常(如
DataAccessException)给 Service,必须转换为业务异常或可选结果(Optional / 空集合)。
1.4 选型权衡与风险点
| 决策点 | 推荐方案 | 风险/代价 |
|---|---|---|
| 接口抽象粒度 | 按聚合根划分 | 过粗导致 Service 侵入 SQL,过细导致实现爆炸 |
| 实现方式 | Spring Data + 自定义 Impl 组合 | ORM 耦合泄露到 Impl 层,测试时需 Mock 更多 |
| 返回类型 | 优先 Optional<T> / List<T> |
返回 null 或原始类型会破坏调用方契约 |
| 跨数据源 | Repository 屏蔽多源聚合 | 分布式事务一致性需额外协调 |
常见误解:Repository 不是“对 DAO 的一层包装”,而是业务导向的集合操作接口。如果 Repository 接口方法与 DAO 方法一一对应,说明分层边界已经退化。
1.5 落地步骤(初始阶段)
- 识别聚合根:在领域模型中圈定需独立数据访问的实体(如 Order、User、Product);
- 定义 Repository 接口:放在
domain/repository/包,只包含业务语义方法; - 编写声明式接口:利用 Spring Data 或类似框架声明标准查询;
- 为复杂查询提供自定义实现:通过 Impl 类注入 DAO 或 EntityManager;
- 单元测试接口契约:使用内存实现或 Mock 验证 Service 层不依赖具体存储。
1.6 验收标准
- 替换测试:将 Repository Impl 切换为内存实现后,Service 层全部单测零修改通过;
- 编译隔离:Service 层未直接引用任何 DAO / ORM / JDBC 类;
- 异常验收:Repository 层未抛出
SQLException/PersistenceException到外层; - 方法数量:Repository 接口方法数
≤ 聚合根关联操作数 + 2(按 ID 查找 + 保存/删除)。