Jakarta Persistence, Hibernate, and Spring Data JPA

Last update: 2026-03-29 19:32:52 +0800 +0800
Available translations: 日本語 / 中文(简体) / 中文(繁體)

Jakarta Persistence defines the standard Java API for object-relational mapping. Hibernate is a widely used implementation. Spring Data JPA builds repository abstractions on top of a Jakarta Persistence provider.

The Jakarta Persistence Model #

An application maps ordinary classes to database tables with annotations such as @Entity, @Table, @Id, and @Column:

java
@Entity
@Table(name = "orders")
public class PurchaseOrder {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String status;
}

The standard APIs live in jakarta.persistence. An implementation discovers a jakarta.persistence.spi.PersistenceProvider through Java’s service-provider mechanism. The provider translates persistence operations and JPQL or Criteria queries into database-specific SQL.

In a standalone application, define a persistence unit in META-INF/persistence.xml, create an EntityManagerFactory, and close it when the application stops:

java
EntityManagerFactory emf =
        Persistence.createEntityManagerFactory("application");
try {
    EntityManager em = emf.createEntityManager();
    // begin and commit a transaction around changes
    em.close();
} finally {
    emf.close();
}

The persistence unit supplies the provider, managed entity classes, data source or JDBC settings, and provider properties. Prefer a container-managed data source and externalized credentials rather than embedding database passwords in persistence.xml.

Entity Managers, Transactions, and Queries #

An EntityManager represents a persistence context: within that context, one managed Java object identity corresponds to a database identity. Persist, merge, remove, and query entities inside an appropriate transaction. An EntityManagerFactory is expensive and application-scoped; an EntityManager is usually request- or transaction-scoped and is not thread-safe.

JPQL queries entity names and properties, not tables and columns:

java
List<PurchaseOrder> orders = em.createQuery(
        "select o from PurchaseOrder o where o.status = :status",
        PurchaseOrder.class)
    .setParameter("status", "PAID")
    .getResultList();

Use named parameters instead of concatenating input into JPQL. The Criteria API offers a programmatic alternative for dynamic queries.

Hibernate #

Hibernate implements Jakarta Persistence and also exposes optional native features. Start with the standard API to keep portability. Use Hibernate extensions only where their value is clear and document the resulting vendor dependency.

Lazy associations defer fetching until accessed. This avoids unnecessary work but can cause LazyInitializationException outside a persistence context and the N+1 query problem inside one. Design fetch plans explicitly with fetch joins, entity graphs, batching, or projections; do not solve every problem by making all associations eager.

Schema generation is convenient for local development, but production schema changes should be reviewed and applied through a migration tool.

Spring Data JPA Repositories #

Spring Data can generate repository implementations for interfaces that extend Repository, commonly JpaRepository:

java
public interface PurchaseOrderRepository
        extends JpaRepository<PurchaseOrder, Long> {
    List<PurchaseOrder> findByStatus(String status);
}

Spring discovers repositories through configuration or Boot auto-configuration and manages their lifecycle as beans. JpaRepository provides CRUD, paging, and sorting methods. Derived query names are useful for simple predicates; use @Query, Specifications, or a custom repository when a method name would become unclear.

Transaction boundaries belong in the service layer for business operations that involve multiple repositories or external effects. Read-only transactions can communicate intent and permit provider optimizations, but they are not a security mechanism.

Comments

Read or comment on GitHub (sign-in required to comment)