Best Practices Checklist

Mapping

  • All associations LAZY (@ManyToOne and @OneToOne are EAGER by default: change them).
  • Use SEQUENCE ids with allocationSize for batching (or UUIDs generated in Java).
  • Prefer unidirectional @ManyToOne; add the inverse @OneToMany only for small, bounded children (order items), with add/remove helper methods.
  • Proxy-safe equals/hashCode; hand-written toString without associations.
  • @Version on entities users edit concurrently.

Queries and Transactions

  • spring.jpa.open-in-view=false.
  • @Transactional on service methods, readOnly = true for reads; no remote calls inside transactions.
  • DTO projections for API responses and lists; entities only when you modify them.
  • Paginate every list; never findAll() on a growing table.
  • Bulk changes: JDBC batching + flush/clear, or bulk JPQL/SQL updates.

Operations

  • ddl-auto=validate + Flyway/Liquibase; expand/contract for live changes.
  • Statistics and slow-query logging in non-production; query count assertions in tests.
  • Repository tests on the real database engine with Testcontainers.
  • Second-level cache only for read-mostly data, measured by hit ratio.
  • Indexes for every foreign key and every filtered/sorted column; check with EXPLAIN.

Tip: Most JPA performance problems come from three things: N+1 queries, loading too much (EAGER, entities instead of DTOs, no paging), and long sessions with thousands of managed entities. Check these three first.