我是Hibernate的新手,我不确定是否使用Hibernate SessionFactory或JPA EntityManagerFactory来创建Hibernate会话。

这两者有什么不同?使用这些工具的优缺点是什么?


当前回答

SessionFactory vs. EntityManagerFactory

正如我在Hibernate用户指南中解释的那样,Hibernate SessionFactory扩展了JPA EntityManagerFactory,如下图所示:

因此,SessionFactory也是一个JPA EntityManagerFactory。

SessionFactory和EntityManagerFactory都包含实体映射元数据,并允许您创建Hibernate Session或EntityManager。

Session vs. EntityManager

就像SessionFactory和EntityManagerFactory一样,Hibernate Session扩展了JPA EntityManager。因此,EntityManager定义的所有方法都可以在Hibernate会话中使用。

Session和EntityManager将实体状态转换为SQL语句,如SELECT、INSERT、UPDATE和DELETE。

Hibernate和JPA引导

当引导JPA或Hibernate应用程序时,您有两个选择:

您可以通过Hibernate原生机制进行引导,并通过BootstrapServiceRegistryBuilder创建SessionFactory。如果您使用Spring, Hibernate引导是通过LocalSessionFactoryBean完成的,如GitHub示例所示。 或者,您可以通过持久化类或EntityManagerFactoryBuilder创建JPA EntityManagerFactory。如果您正在使用Spring, JPA引导是通过LocalContainerEntityManagerFactoryBean完成的,正如这个GitHub示例所示。

通过JPA引导是首选的。这是因为JPA FlushModeType。AUTO是一个比传统的FlushMode更好的选择。AUTO,它破坏了本地SQL查询的读写一致性。

将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接口。

其他回答

通过使用EntityManager,代码不再与hibernate紧密耦合。但是对于这种情况,在用法中我们应该使用:

javax.persistence.EntityManager

而不是

org.hibernate.ejb.HibernateEntityManager

类似地,对于EntityManagerFactory,使用javax接口。这样,代码是松散耦合的。如果有一个比hibernate更好的JPA 2实现,那么转换将很容易。在极端情况下,我们可以将类型转换为HibernateEntityManager。

EntityManagerFactory是标准实现,它在所有实现中都是一样的。如果您将ORM迁移到任何其他提供者(如EclipseLink),则处理事务的方法不会有任何变化。相反,如果使用hibernate的会话工厂,它就绑定到hibernate api,不能迁移到新的供应商。

使用EntityManagerFactory方法允许我们使用回调方法注释,如@PrePersist, @PostPersist,@PreUpdate,而不需要额外的配置。

在使用SessionFactory时使用类似的回调将需要额外的努力。

相关Hibernate文档可以在这里和这里找到。

有关SOF问题和春季论坛讨论

我想补充一点,你也可以通过从EntityManager调用getDelegate()方法来获取Hibernate的会话。

ex:

Session session = (Session) entityManager.getDelegate();

SessionFactory vs. EntityManagerFactory

正如我在Hibernate用户指南中解释的那样,Hibernate SessionFactory扩展了JPA EntityManagerFactory,如下图所示:

因此,SessionFactory也是一个JPA EntityManagerFactory。

SessionFactory和EntityManagerFactory都包含实体映射元数据,并允许您创建Hibernate Session或EntityManager。

Session vs. EntityManager

就像SessionFactory和EntityManagerFactory一样,Hibernate Session扩展了JPA EntityManager。因此,EntityManager定义的所有方法都可以在Hibernate会话中使用。

Session和EntityManager将实体状态转换为SQL语句,如SELECT、INSERT、UPDATE和DELETE。

Hibernate和JPA引导

当引导JPA或Hibernate应用程序时,您有两个选择:

您可以通过Hibernate原生机制进行引导,并通过BootstrapServiceRegistryBuilder创建SessionFactory。如果您使用Spring, Hibernate引导是通过LocalSessionFactoryBean完成的,如GitHub示例所示。 或者,您可以通过持久化类或EntityManagerFactoryBuilder创建JPA EntityManagerFactory。如果您正在使用Spring, JPA引导是通过LocalContainerEntityManagerFactoryBean完成的,正如这个GitHub示例所示。

通过JPA引导是首选的。这是因为JPA FlushModeType。AUTO是一个比传统的FlushMode更好的选择。AUTO,它破坏了本地SQL查询的读写一致性。

将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接口。