JPA/Hibernate Patterns 是一套面向 Spring Boot 的 JPA/Hibernate 实践模式,用于数据建模、Repository 编写与性能调优。
适用场景
在以下情况启用:设计 JPA 实体与表映射;定义关系(@OneToMany、@ManyToOne、@ManyToMany);优化查询(N+1 预防、fetch 策略、投影);配置事务、审计或软删除;设置分页、排序或自定义 Repository 方法;调优连接池(HikariCP)或二级缓存。
实体设计
使用 @Entity 与 @Table 定义表名和索引,例如为 slug 列建立唯一索引 idx_markets_slug。通过 @EntityListeners(AuditingEntityListener.class) 启用审计监听。主键使用 @Id 与 @GeneratedValue(strategy = GenerationType.IDENTITY)。字段用 @Column 约束 nullable、length、unique;枚举用 @Enumerated(EnumType.STRING);审计时间戳用 @CreatedDate 与 @LastModifiedDate。
启用审计需添加配置类:@Configuration 与 @EnableJpaAuditing。
关系与 N+1 预防
集合关系使用 @OneToMany(mappedBy = "market", cascade = CascadeType.ALL, orphanRemoval = true)。默认使用懒加载;需要时在查询中使用 JOIN FETCH。避免在集合上使用 EAGER;读路径使用 DTO 投影。示例查询:@Query("select m from MarketEntity m left join fetch m.positions where m.id = :id")。
Repository 模式
继承 JpaRepository,可定义派生查询方法如 findBySlug。使用 @Query 配合 Pageable 实现分页查询。轻量查询使用投影接口,例如定义 MarketSummary 接口包含 getId、getName、getStatus,并返回 Page<MarketSummary>。
事务
在服务方法上标注 @Transactional。读路径使用 @Transactional(readOnly = true) 以优化。谨慎选择传播行为,避免长事务。示例:在 @Transactional 方法中通过 findById 获取实体,不存在则抛出 EntityNotFoundException,修改状态后返回。
分页
使用 PageRequest.of(pageNumber, pageSize, Sort.by("createdAt").descending()) 构造分页请求。类似游标的分页可在 JPQL 中加入 id > :lastId 并配合排序。
索引与性能
为常见过滤字段(status、slug、外键)添加索引。使用与查询模式匹配的复合索引(如 status、created_at)。避免 select *,只投影所需列。批量写入使用 saveAll 并配置 hibernate.jdbc.batch_size。
连接池(HikariCP)
推荐属性:spring.datasource.hikari.maximum-pool-size=20、minimum-idle=5、connection-timeout=30000、validation-timeout=5000。针对 PostgreSQL LOB 处理,添加 spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true。
缓存
一级缓存按 EntityManager 生效;避免跨事务持有实体。读密集实体可谨慎考虑二级缓存,并验证逐出策略。
迁移
使用 Flyway 或 Liquibase;生产环境不要依赖 Hibernate 自动 DDL。迁移应保持幂等与增量,避免无计划地删除列。
测试数据访问
优先使用 @DataJpaTest 配合 Testcontainers 以贴近生产环境。通过日志断言 SQL 效率:设置 logging.level.org.hibernate.SQL=DEBUG 与 logging.level.org.hibernate.orm.jdbc.bind=TRACE 查看参数值。
核心原则:保持实体精简、查询有意图、事务短小;用 fetch 策略与投影防止 N+1,并针对读写路径建立索引。