Skip to content

Spring Data JPA 实战建议

Spring Data JPA 写 CRUD 很快,但实战中不能把 Entity、接口 DTO、事务、关联关系和复杂查询混在一起。否则项目早期很省事,后期会出现 SQL 不可控、懒加载异常、循环引用和性能问题。

本页偏项目边界和实践规则。Repository 代理、查询解析、DTO 投影、分页 count 和慢查询排查的完整过程见 Spring Data JPA 核心全过程原理

推荐分层

mermaid
flowchart TD
    A["Controller"] --> B["Request DTO"]
    B --> C["Service 业务逻辑"]
    C --> D["Repository 数据访问"]
    D --> E["Entity 持久化模型"]
    C --> F["Response DTO"]
    F --> A

职责:

做什么
Controller接收请求和返回响应
DTO表达接口入参和出参
Service业务规则、事务边界
Repository数据访问
Entity数据库持久化映射

不要直接返回 Entity

直接返回 Entity 的问题:

  1. 可能暴露数据库字段。
  2. 可能触发懒加载异常。
  3. 双向关联可能导致 JSON 循环引用。
  4. 接口结构和数据库结构强绑定。

推荐转换 DTO:

java
public record UserDetail(Long id, String username) {
    public static UserDetail from(User user) {
        return new UserDetail(user.getId(), user.getUsername());
    }
}

关联关系要克制

JPA 支持一对多、多对一、多对多,但不要为了“对象模型好看”滥用关联。

建议:

  1. 多对一相对常用,一对多谨慎。
  2. 多对多通常拆成中间实体。
  3. 列表查询避免加载大集合。
  4. 复杂列表优先 DTO 查询。
  5. 关键接口必须看最终 SQL。

事务建议

java
@Transactional
public void createOrder(CreateOrderRequest request) {
    // 读取、校验、修改、保存都在一个业务事务内
}

事务边界建议:

  • 写操作放 Service。
  • 不要把事务放 Controller。
  • 事务内不要做慢远程调用。
  • 只读查询可以标注 readOnly = true
  • 批量任务分批提交,避免长事务。

查询建议

场景推荐方式
简单唯一查询方法名查询
固定复杂查询@Query JPQL
数据库特性原生 SQL
动态筛选Specification
列表展示DTO 投影
报表统计评估 MyBatis、原生 SQL 或数仓

SQL 日志

开发和测试环境建议打开 SQL 日志,观察 JPA 生成的真实 SQL。

yaml
spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true

生产环境不要无节制打印完整 SQL 和参数,避免日志量和敏感信息问题。

测试建议

测试关注点
Service 单元测试业务规则
Repository 集成测试查询是否正确
SQL 性能测试慢查询、索引、分页
事务测试回滚、传播行为

Repository 查询尤其要覆盖空条件、边界条件和分页排序。

常见坑

问题后果建议
Entity 返回接口字段暴露、懒加载、循环引用转 DTO
关联映射过多SQL 不可控只建必要关联
不看 SQL性能问题隐藏开启日志和执行计划
大量方法名查询维护困难复杂查询换方案
事务范围过大锁等待和连接占用缩小事务

小结

Spring Data JPA 实战的关键是边界清晰:Entity 管持久化,DTO 管接口,Service 管事务和业务,Repository 管数据访问。JPA 能提高开发效率,但必须持续关注最终 SQL、关联加载和事务边界。

实战流程原理

mermaid
flowchart TD
    A["Controller 接收请求"] --> B["Service 校验并开启事务"]
    B --> C["Repository 访问数据库"]
    C --> D["Entity 托管和脏检查"]
    D --> E["转换 DTO"]
    E --> F["返回接口"]

为什么要分层:Controller 不应该直接操作 Entity,Repository 不应该写业务决策,Service 负责事务和业务规则。分层清楚后,JPA 的自动持久化能力才不会变成隐式副作用。

继续深入:Spring Data JPA 核心全过程原理