Jakarta Persistence、Hibernate 和 Spring Data JPA

最后更新: 2026-03-29 19:32:52 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

Jakarta Persistence 定义了用于对象关系映射的标准 Java API。Hibernate 是一种广泛使用的实现。Spring Data JPA 在 Jakarta Persistence 提供程序之上构建仓储抽象。

Jakarta Persistence 模型 #

应用程序使用 @Entity、@Table、@Id 和 @Column 等注解,将普通类映射到数据库表:

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

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

标准 API 位于 jakarta.persistence 中。实现通过 Java 的服务提供程序机制发现 jakarta.persistence.spi.PersistenceProvider。提供程序将持久化操作以及 JPQL 或 Criteria 查询转换为特定于数据库的 SQL。

在独立应用程序中,应在 META-INF/persistence.xml 中定义持久化单元,创建 EntityManagerFactory,并在应用程序停止时将其关闭:

java
EntityManagerFactory emf =
        Persistence.createEntityManagerFactory("application");
try {
    EntityManager em = emf.createEntityManager();
    // 在变更操作外层开始并提交事务
    em.close();
} finally {
    emf.close();
}

持久化单元提供提供程序、受管理的实体类、数据源或 JDBC 设置,以及提供程序属性。应优先使用容器管理的数据源和外部化的凭据,而不是将数据库密码嵌入 persistence.xml。

实体管理器、事务和查询 #

EntityManager 表示一个持久化上下文:在该上下文中,一个受管理的 Java 对象标识对应一个数据库标识。应在适当的事务中持久化、合并、删除和查询实体。EntityManagerFactory 创建成本较高,作用域为应用程序;EntityManager 通常具有请求作用域或事务作用域,并且不是线程安全的。

JPQL 查询的是实体名称和属性,而不是表和列:

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

应使用命名参数,而不是将输入拼接到 JPQL 中。Criteria API 为动态查询提供了编程式替代方案。

Hibernate #

Hibernate 实现了 Jakarta Persistence,同时还提供可选的原生功能。应首先使用标准 API,以保持可移植性。仅在 Hibernate 扩展的价值明确时使用,并记录由此产生的供应商依赖。

延迟关联会将获取操作推迟到访问关联时。这样可以避免不必要的工作,但在持久化上下文之外可能导致 LazyInitializationException,在持久化上下文之内可能导致 N+1 查询问题。应通过 fetch join、实体图、批处理或投影显式设计获取计划;不要通过将所有关联设置为 eager 来解决所有问题。

模式生成便于本地开发,但生产环境中的模式变更应经过审查,并通过迁移工具应用。

Spring Data JPA 仓储 #

Spring Data 可以为扩展 Repository(通常是 JpaRepository)的接口生成仓储实现:

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

Spring 通过配置或 Boot 自动配置发现仓储,并将其生命周期作为 Bean 进行管理。JpaRepository 提供 CRUD、分页和排序方法。派生查询名称适用于简单谓词;如果方法名会变得不清晰,应使用 @Query、Specifications 或自定义仓储。

对于涉及多个仓储或外部作用的业务操作,事务边界应位于服务层。只读事务可以表达意图并允许提供程序进行优化,但不是安全机制。

评论

在 GitHub 上阅读或评论(发表评论需要登录)