我是 Hibernate 的新手,我不确定是使用 Hibernate SessionFactory
还是 JPA EntityManagerFactory
来创建 Hibernate Session
。
这两者有什么区别?使用它们各自的优点和缺点是什么?
首选 EntityManagerFactory
和 EntityManager
。它们由 JPA 标准定义。
SessionFactory
和 Session
是特定于休眠的。 EntityManager
在后台调用休眠会话。如果您需要EntityManager
中没有的一些特定功能,您可以通过调用获取会话:
Session session = entityManager.unwrap(Session.class);
SessionFactory 与 EntityManagerFactory
正如我在 Hibernate User Guide 中解释的那样,Hibernate SessionFactory
扩展了 JPA EntityManagerFactory
,如下图所示:
https://i.stack.imgur.com/5aTCH.png
因此,SessionFactory
也是 JPA EntityManagerFactory
。
SessionFactory
和 EntityManagerFactory
都包含实体映射元数据,并允许您创建 Hibernate Session
或 EntityManager
。
Session 与 EntityManager
与 SessionFactory
和 EntityManagerFactory
一样,Hibernate Session
扩展了 JPA EntityManager
。因此,由 EntityManager
定义的所有方法都在 Hibernate Session
中可用。
Session
和 `EntityManager 将 entity state transitions 转换为 SQL 语句,如 SELECT、INSERT、UPDATE 和 DELETE。
Hibernate 与 JPA 引导程序
在引导 JPA 或 Hibernate 应用程序时,您有两种选择:
您可以通过 Hibernate 原生机制进行引导,并通过 BootstrapServiceRegistryBuilder 创建一个 SessionFactory。如果您使用的是 Spring,Hibernate 引导是通过 LocalSessionFactoryBean 完成的,如此 GitHub 示例所示。或者,您可以通过 Persistence 类或 EntityManagerFactoryBuilder 创建 JPA EntityManagerFactory。如果您使用的是 Spring,则 JPA 引导是通过 LocalContainerEntityManagerFactoryBean 完成的,如此 GitHub 示例所示。
通过 JPA 引导是首选。这是因为 JPA FlushModeType.AUTO
是比旧版 FlushMode.AUTO
更好的选择,旧版 breaks read-your-writes consistency for native SQL queries。
将 JPA 解包到 Hibernate
此外,如果您通过 JPA 引导,并且您已经通过 @PersistenceUnit
注释注入了 EntityManagerFactory
:
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
您可以使用 unwrap
方法轻松访问底层 Sessionfactory
:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
JPA EntityManager
也可以做到这一点。如果您通过 @PersistenceContext
注释注入 EntityManager
:
@PersistenceContext
private EntityManager entityManager;
您可以使用 unwrap
方法轻松访问底层 Session
:
Session session = entityManager.unwrap(Session.class);
结论
因此,您应该通过 JPA 引导,使用 EntityManagerFactory
和 EntityManager
,并且仅当您想要访问 JPA 中不可用的某些特定于 Hibernate 的方法(例如获取实体)时,才将它们解包到其关联的 Hibernate 接口通过其 natural identifier。
我更喜欢 JPA2 EntityManager
API 而不是 SessionFactory
,因为它感觉更现代。一个简单的例子:
JPA:
@PersistenceContext
EntityManager entityManager;
public List<MyEntity> findSomeApples() {
return entityManager
.createQuery("from MyEntity where apples=7", MyEntity.class)
.getResultList();
}
会话工厂:
@Autowired
SessionFactory sessionFactory;
public List<MyEntity> findSomeApples() {
Session session = sessionFactory.getCurrentSession();
List<?> result = session.createQuery("from MyEntity where apples=7")
.list();
@SuppressWarnings("unchecked")
List<MyEntity> resultCasted = (List<MyEntity>) result;
return resultCasted;
}
我认为很明显,第一个看起来更干净,也更容易测试,因为 EntityManager 可以很容易地模拟。
return sessionFactory.getCurrentSession().createQuery("from User where id=1").list()
使用 EntityManagerFactory 方法允许我们使用回调方法注释,如 @PrePersist、@PostPersist、@PreUpdate,而无需额外配置。
在使用 SessionFactory 时使用类似的回调将需要额外的努力。
可以在 here 和 here 中找到相关的 Hibernate 文档。
Related SOF Question 和 Spring Forum discussion
通过使用 EntityManager,代码不再与休眠紧密耦合。但是为此,在使用中我们应该使用:
javax.persistence.EntityManager
代替
org.hibernate.ejb.HibernateEntityManager
同样,对于 EntityManagerFactory,使用 javax 接口。这样,代码是松耦合的。如果有比 hibernate 更好的 JPA 2 实现,切换会很容易。在极端情况下,我们可以将类型转换为 HibernateEntityManager。
EntityManagerFactory 是标准实现,在所有实现中都是相同的。如果您为任何其他提供商(如 EclipseLink)迁移 ORM,则处理事务的方法不会发生任何变化。相反,如果您使用 hibernate 的会话工厂,它与 hibernate API 绑定,无法迁移到新的供应商。
EntityManager 接口类似于 hibernate 中的 sessionFactory。 EntityManager 在 javax.persistance 包下,但 session 和 sessionFactory 在 org.hibernate.Session/sessionFactory 包下。
实体管理器是特定于 JPA 的,而 session/sessionFactory 是特定于休眠的。
EntityManager
获取Session
的方法是否与SessionFactory.getCurrentSession()
相同?我的意思是,如果它尚未创建,它会打开新的Session
吗?它在多线程环境中如何工作?