1. 概述

在JPA规范中,PersistenceUnitPersistenceContext是两个核心但容易混淆的概念。本文将通过代码示例和实际场景,对比二者的区别与联系,帮助开发者避免常见踩坑点。✅

核心区别速览

概念 作用域 管理者 生命周期
PersistenceUnit 应用级 EntityManagerFactory 应用启动时创建
PersistenceContext 事务级 EntityManager 事务开始时创建

2. EntityManager 和 EntityManagerFactory

2.1 EntityManagerFactory 基础

EntityManagerFactory对应JPA中的PersistenceUnit,是重量级对象,负责管理数据库连接池和全局配置。通常在应用启动时初始化,整个应用共享一个实例。

// 创建EntityManagerFactory(对应PersistenceUnit)
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit");

// 配置示例(persistence.xml)
<persistence-unit name="myPersistenceUnit" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>java:/MyDataSource</jta-data-source>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
    </properties>
</persistence-unit>

⚠️ 关键点

  • 一个PersistenceUnit对应一个数据库连接池
  • 线程安全,但创建成本高(避免重复创建)
  • 通过@PersistenceUnit注解注入时,实际注入的是EntityManagerFactory

2.2 EntityManager 基础

EntityManager对应PersistenceContext,是轻量级对象,管理实体对象的生命周期和持久化操作。每个事务通常创建一个新实例。

// 获取EntityManager(对应PersistenceContext)
EntityManager em = emf.createEntityManager();

// 使用示例
EntityTransaction transaction = em.getTransaction();
try {
    transaction.begin();
    User user = new User("john.doe@example.com");
    em.persist(user); // 持久化操作
    transaction.commit();
} finally {
    em.close(); // 必须手动关闭
}

常见错误

// 错误示范:跨线程共享EntityManager
public class UserService {
    @PersistenceContext
    private EntityManager em; // 容器管理的线程安全代理
    
    public void updateUser() {
        // 在事务方法中自动绑定当前线程的PersistenceContext
    }
}

2.3 二者关系图

graph TD
    A[应用启动] --> B[创建EntityManagerFactory]
    B --> C{事务开始}
    C --> D[创建EntityManager]
    D --> E[操作PersistenceContext]
    E --> F{事务结束}
    F --> G[关闭EntityManager]
    B --> H[应用关闭]
    H --> I[关闭EntityManagerFactory]

2.4 最佳实践总结

推荐做法

  1. 单例模式EntityManagerFactory在应用启动时初始化,全局唯一
  2. 请求/事务范围EntityManager按需创建(如Spring的@Transactional
  3. 显式关闭:非容器环境下手动关闭EntityManagerEntityManagerFactory

避坑指南

  • 永远不要在多线程间共享EntityManager实例
  • 避免在循环中创建EntityManagerFactory(会导致连接池泄漏)
  • 使用@PersistenceContext而非@PersistenceUnit注入(除非明确需要工厂)

经验之谈:在Spring Boot中,开发者通常直接使用@PersistenceContext,框架已自动处理好二者的生命周期管理。但理解底层机制对排查问题至关重要,特别是遇到连接池耗尽或事务传播异常时。


原始标题:PersistenceUnit vs. PersistenceContext | Baeldung