1. 概述
在JPA规范中,PersistenceUnit
和PersistenceContext
是两个核心但容易混淆的概念。本文将通过代码示例和实际场景,对比二者的区别与联系,帮助开发者避免常见踩坑点。✅
核心区别速览
概念 | 作用域 | 管理者 | 生命周期 |
---|---|---|---|
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 最佳实践总结
✅ 推荐做法:
- 单例模式:
EntityManagerFactory
在应用启动时初始化,全局唯一 - 请求/事务范围:
EntityManager
按需创建(如Spring的@Transactional
) - 显式关闭:非容器环境下手动关闭
EntityManager
和EntityManagerFactory
❌ 避坑指南:
- 永远不要在多线程间共享
EntityManager
实例 - 避免在循环中创建
EntityManagerFactory
(会导致连接池泄漏) - 使用
@PersistenceContext
而非@PersistenceUnit
注入(除非明确需要工厂)
经验之谈:在Spring Boot中,开发者通常直接使用
@PersistenceContext
,框架已自动处理好二者的生命周期管理。但理解底层机制对排查问题至关重要,特别是遇到连接池耗尽或事务传播异常时。