Spring Data JPA 最佳实践2025 实战指南JPA 不是银弹但它确实能让我们更专注于业务逻辑。作为一名 Java 架构师我见过太多因 JPA 使用不当导致的性能问题。从 N1 查询到内存溢出从事务管理到缓存策略每一个问题都可能给系统带来严重的性能瓶颈。今天分享一套 2025 年最新的 Spring Data JPA 最佳实践。一、基础配置优化1.1 依赖管理Maven 配置dependencies !-- Spring Data JPA -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- 数据库驱动 -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency !-- HikariCP 连接池 -- dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId /dependency /dependencies1.2 数据源配置# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/order_db?useSSLfalseserverTimezoneUTC username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 5 idle-timeout: 30000 connection-timeout: 20000 max-lifetime: 1800000 jpa: hibernate: ddl-auto: update show-sql: false properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect jdbc.lob.non_contextual_creation: true generate_statistics: true二、实体设计最佳实践2.1 基本注解Entity Table(name orders) Data NoArgsConstructor AllArgsConstructor Builder public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(name order_number, unique true, nullable false, length 50) private String orderNumber; Column(name customer_id, nullable false) private Long customerId; Column(name total_amount, precision 10, scale 2, nullable false) private BigDecimal totalAmount; Column(name status, length 20, nullable false) private String status; Column(name created_at, nullable false, updatable false) CreatedDate private LocalDateTime createdAt; Column(name updated_at) LastModifiedDate private LocalDateTime updatedAt; }2.2 关联关系// 一对多关系 Entity public class Customer { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String name; // 推荐使用 LAZY 加载 OneToMany(mappedBy customer, fetch FetchType.LAZY, cascade CascadeType.ALL) private ListOrder orders; } // 多对一关系 Entity public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; // 推荐使用 LAZY 加载 ManyToOne(fetch FetchType.LAZY) JoinColumn(name customer_id, nullable false) private Customer customer; } // 多对多关系 Entity public class Product { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String name; ManyToMany(fetch FetchType.LAZY) JoinTable( name product_category, joinColumns JoinColumn(name product_id), inverseJoinColumns JoinColumn(name category_id) ) private SetCategory categories; }2.3 继承策略// 单表继承 Inheritance(strategy InheritanceType.SINGLE_TABLE) DiscriminatorColumn(name type, discriminatorType DiscriminatorType.STRING) DiscriminatorValue(payment) Entity public abstract class Payment { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private BigDecimal amount; private String status; } Entity DiscriminatorValue(credit_card) public class CreditCardPayment extends Payment { private String cardNumber; private String expiryDate; } Entity DiscriminatorValue(paypal) public class PayPalPayment extends Payment { private String paypalEmail; }三、Repository 设计3.1 基本 RepositoryRepository public interface OrderRepository extends JpaRepositoryOrder, Long { // 方法命名查询 ListOrder findByStatus(String status); ListOrder findByCustomerIdAndStatus(Long customerId, String status); OptionalOrder findByOrderNumber(String orderNumber); // 分页查询 PageOrder findByCustomerId(Long customerId, Pageable pageable); // 计数查询 long countByStatus(String status); // 删除查询 void deleteByStatus(String status); }3.2 自定义查询Repository public interface OrderRepository extends JpaRepositoryOrder, Long { // JPQL 查询 Query(SELECT o FROM Order o WHERE o.customerId :customerId AND o.status :status) ListOrder findByCustomerIdAndStatusCustom(Param(customerId) Long customerId, Param(status) String status); // 原生 SQL 查询 Query(value SELECT * FROM orders WHERE customer_id :customerId AND status :status, nativeQuery true) ListOrder findByCustomerIdAndStatusNative(Param(customerId) Long customerId, Param(status) String status); // 带有分页的查询 Query(SELECT o FROM Order o WHERE o.totalAmount :amount) PageOrder findByTotalAmountGreaterThan(Param(amount) BigDecimal amount, Pageable pageable); // 更新查询 Modifying Query(UPDATE Order o SET o.status :status WHERE o.id :id) int updateStatus(Param(id) Long id, Param(status) String status); // 删除查询 Modifying Query(DELETE FROM Order o WHERE o.status :status) int deleteByStatusCustom(Param(status) String status); }3.3 自定义 Repository 实现// 自定义接口 public interface OrderRepositoryCustom { ListOrder findOrdersWithItems(Long customerId); void updateOrderStatusBatch(ListLong orderIds, String status); } // 实现类 Repository public class OrderRepositoryImpl implements OrderRepositoryCustom { private final EntityManager entityManager; public OrderRepositoryImpl(EntityManager entityManager) { this.entityManager entityManager; } Override public ListOrder findOrdersWithItems(Long customerId) { String jpql SELECT o FROM Order o JOIN FETCH o.items WHERE o.customerId :customerId; return entityManager.createQuery(jpql, Order.class) .setParameter(customerId, customerId) .getResultList(); } Override public void updateOrderStatusBatch(ListLong orderIds, String status) { String jpql UPDATE Order o SET o.status :status WHERE o.id IN :orderIds; entityManager.createQuery(jpql) .setParameter(status, status) .setParameter(orderIds, orderIds) .executeUpdate(); } } // 主 Repository 接口 Repository public interface OrderRepository extends JpaRepositoryOrder, Long, OrderRepositoryCustom { // 继承的方法 }四、性能优化4.1 延迟加载与急加载// 延迟加载默认 ManyToOne(fetch FetchType.LAZY) JoinColumn(name customer_id) private Customer customer; // 急加载 ManyToOne(fetch FetchType.EAGER) JoinColumn(name customer_id) private Customer customer; // 使用 EntityGraph 控制加载 EntityGraph(attributePaths {items, customer}) Query(SELECT o FROM Order o WHERE o.id :id) OptionalOrder findByIdWithDetails(Param(id) Long id); // 使用 NamedEntityGraph NamedEntityGraph(name Order.withItems, attributeNodes NamedAttributeNode(items)) Entity public class Order { // ... } // 在 Repository 中使用 EntityGraph(value Order.withItems) OptionalOrder findById(Long id);4.2 批处理// 批量插入 Service public class OrderService { private final EntityManager entityManager; Transactional public void batchInsert(ListOrder orders) { for (int i 0; i orders.size(); i) { entityManager.persist(orders.get(i)); // 每 50 个实体刷新一次 if (i % 50 0) { entityManager.flush(); entityManager.clear(); } } // 最后一次刷新 entityManager.flush(); entityManager.clear(); } } // 批量更新 Modifying Query(UPDATE Order o SET o.status :status WHERE o.id IN :ids) int updateStatusBatch(Param(ids) ListLong ids, Param(status) String status); // 使用 Spring Batch Bean public Job importOrdersJob() { return jobBuilderFactory.get(importOrdersJob) .incrementer(new RunIdIncrementer()) .flow(step1()) .end() .build(); } Bean public Step step1() { return stepBuilderFactory.get(step1) .Order, Orderchunk(100) .reader(orderReader()) .processor(orderProcessor()) .writer(orderWriter()) .build(); }4.3 缓存策略// 二级缓存配置 Entity Cacheable org.hibernate
Spring Data JPA 最佳实践:2025 实战指南
发布时间:2026/5/27 3:32:55
Spring Data JPA 最佳实践2025 实战指南JPA 不是银弹但它确实能让我们更专注于业务逻辑。作为一名 Java 架构师我见过太多因 JPA 使用不当导致的性能问题。从 N1 查询到内存溢出从事务管理到缓存策略每一个问题都可能给系统带来严重的性能瓶颈。今天分享一套 2025 年最新的 Spring Data JPA 最佳实践。一、基础配置优化1.1 依赖管理Maven 配置dependencies !-- Spring Data JPA -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- 数据库驱动 -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency !-- HikariCP 连接池 -- dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId /dependency /dependencies1.2 数据源配置# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/order_db?useSSLfalseserverTimezoneUTC username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 5 idle-timeout: 30000 connection-timeout: 20000 max-lifetime: 1800000 jpa: hibernate: ddl-auto: update show-sql: false properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL8Dialect jdbc.lob.non_contextual_creation: true generate_statistics: true二、实体设计最佳实践2.1 基本注解Entity Table(name orders) Data NoArgsConstructor AllArgsConstructor Builder public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(name order_number, unique true, nullable false, length 50) private String orderNumber; Column(name customer_id, nullable false) private Long customerId; Column(name total_amount, precision 10, scale 2, nullable false) private BigDecimal totalAmount; Column(name status, length 20, nullable false) private String status; Column(name created_at, nullable false, updatable false) CreatedDate private LocalDateTime createdAt; Column(name updated_at) LastModifiedDate private LocalDateTime updatedAt; }2.2 关联关系// 一对多关系 Entity public class Customer { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String name; // 推荐使用 LAZY 加载 OneToMany(mappedBy customer, fetch FetchType.LAZY, cascade CascadeType.ALL) private ListOrder orders; } // 多对一关系 Entity public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; // 推荐使用 LAZY 加载 ManyToOne(fetch FetchType.LAZY) JoinColumn(name customer_id, nullable false) private Customer customer; } // 多对多关系 Entity public class Product { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String name; ManyToMany(fetch FetchType.LAZY) JoinTable( name product_category, joinColumns JoinColumn(name product_id), inverseJoinColumns JoinColumn(name category_id) ) private SetCategory categories; }2.3 继承策略// 单表继承 Inheritance(strategy InheritanceType.SINGLE_TABLE) DiscriminatorColumn(name type, discriminatorType DiscriminatorType.STRING) DiscriminatorValue(payment) Entity public abstract class Payment { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private BigDecimal amount; private String status; } Entity DiscriminatorValue(credit_card) public class CreditCardPayment extends Payment { private String cardNumber; private String expiryDate; } Entity DiscriminatorValue(paypal) public class PayPalPayment extends Payment { private String paypalEmail; }三、Repository 设计3.1 基本 RepositoryRepository public interface OrderRepository extends JpaRepositoryOrder, Long { // 方法命名查询 ListOrder findByStatus(String status); ListOrder findByCustomerIdAndStatus(Long customerId, String status); OptionalOrder findByOrderNumber(String orderNumber); // 分页查询 PageOrder findByCustomerId(Long customerId, Pageable pageable); // 计数查询 long countByStatus(String status); // 删除查询 void deleteByStatus(String status); }3.2 自定义查询Repository public interface OrderRepository extends JpaRepositoryOrder, Long { // JPQL 查询 Query(SELECT o FROM Order o WHERE o.customerId :customerId AND o.status :status) ListOrder findByCustomerIdAndStatusCustom(Param(customerId) Long customerId, Param(status) String status); // 原生 SQL 查询 Query(value SELECT * FROM orders WHERE customer_id :customerId AND status :status, nativeQuery true) ListOrder findByCustomerIdAndStatusNative(Param(customerId) Long customerId, Param(status) String status); // 带有分页的查询 Query(SELECT o FROM Order o WHERE o.totalAmount :amount) PageOrder findByTotalAmountGreaterThan(Param(amount) BigDecimal amount, Pageable pageable); // 更新查询 Modifying Query(UPDATE Order o SET o.status :status WHERE o.id :id) int updateStatus(Param(id) Long id, Param(status) String status); // 删除查询 Modifying Query(DELETE FROM Order o WHERE o.status :status) int deleteByStatusCustom(Param(status) String status); }3.3 自定义 Repository 实现// 自定义接口 public interface OrderRepositoryCustom { ListOrder findOrdersWithItems(Long customerId); void updateOrderStatusBatch(ListLong orderIds, String status); } // 实现类 Repository public class OrderRepositoryImpl implements OrderRepositoryCustom { private final EntityManager entityManager; public OrderRepositoryImpl(EntityManager entityManager) { this.entityManager entityManager; } Override public ListOrder findOrdersWithItems(Long customerId) { String jpql SELECT o FROM Order o JOIN FETCH o.items WHERE o.customerId :customerId; return entityManager.createQuery(jpql, Order.class) .setParameter(customerId, customerId) .getResultList(); } Override public void updateOrderStatusBatch(ListLong orderIds, String status) { String jpql UPDATE Order o SET o.status :status WHERE o.id IN :orderIds; entityManager.createQuery(jpql) .setParameter(status, status) .setParameter(orderIds, orderIds) .executeUpdate(); } } // 主 Repository 接口 Repository public interface OrderRepository extends JpaRepositoryOrder, Long, OrderRepositoryCustom { // 继承的方法 }四、性能优化4.1 延迟加载与急加载// 延迟加载默认 ManyToOne(fetch FetchType.LAZY) JoinColumn(name customer_id) private Customer customer; // 急加载 ManyToOne(fetch FetchType.EAGER) JoinColumn(name customer_id) private Customer customer; // 使用 EntityGraph 控制加载 EntityGraph(attributePaths {items, customer}) Query(SELECT o FROM Order o WHERE o.id :id) OptionalOrder findByIdWithDetails(Param(id) Long id); // 使用 NamedEntityGraph NamedEntityGraph(name Order.withItems, attributeNodes NamedAttributeNode(items)) Entity public class Order { // ... } // 在 Repository 中使用 EntityGraph(value Order.withItems) OptionalOrder findById(Long id);4.2 批处理// 批量插入 Service public class OrderService { private final EntityManager entityManager; Transactional public void batchInsert(ListOrder orders) { for (int i 0; i orders.size(); i) { entityManager.persist(orders.get(i)); // 每 50 个实体刷新一次 if (i % 50 0) { entityManager.flush(); entityManager.clear(); } } // 最后一次刷新 entityManager.flush(); entityManager.clear(); } } // 批量更新 Modifying Query(UPDATE Order o SET o.status :status WHERE o.id IN :ids) int updateStatusBatch(Param(ids) ListLong ids, Param(status) String status); // 使用 Spring Batch Bean public Job importOrdersJob() { return jobBuilderFactory.get(importOrdersJob) .incrementer(new RunIdIncrementer()) .flow(step1()) .end() .build(); } Bean public Step step1() { return stepBuilderFactory.get(step1) .Order, Orderchunk(100) .reader(orderReader()) .processor(orderProcessor()) .writer(orderWriter()) .build(); }4.3 缓存策略// 二级缓存配置 Entity Cacheable org.hibernate