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 核心全过程原理。