【问题标题】:Hibernate SessionFactory vs. JPA EntityManagerFactoryHibernate SessionFactory 与 JPA EntityManagerFactory
【发布时间】:2011-08-04 04:32:56
【问题描述】:

我是 Hibernate 的新手,我不确定是使用 Hibernate SessionFactory 还是 JPA EntityManagerFactory 来创建 Hibernate Session

这两者有什么区别?使用它们各自的优缺点是什么?

【问题讨论】:

标签: java hibernate jpa sessionfactory hibernate-entitymanager


【解决方案1】:

首选EntityManagerFactoryEntityManager。它们由 JPA 标准定义。

SessionFactorySession 是特定于休眠的。 EntityManager 在后台调用休眠会话。而如果你需要一些EntityManager中没有的特定功能,可以通过调用获取会话:

Session session = entityManager.unwrap(Session.class);

【讨论】:

  • @elpisu - 实际上我不推荐。我一直只使用官方文档作为学习资源(至少在过去 2 年中),所以我不知道还有什么可靠的。但是文档已经足够好了。
  • @Bozho 我知道已经很晚了,但是使用 SessionFactory 和 Session 的缺点是什么?为什么首选使用 JPA?谢谢
  • @MickaelMarrache 使用 JPA 优于 Hibernate API,因为它是 Java 企业标准。使用 JPA(并限制自己使用它,而不使用 Hibernate 特定的功能)提高了应用程序的可移植性,即您可以选择切换到不同的持久性框架,而对应用程序的更改最少,只要该框架也符合 JPA 标准.
  • 是否因为它是企业标准而更好?我不信。标准通常发展缓慢且复杂。一些现实生活中的好处呢? JPA 更好,因为它有 TypedQuery,可以阻止你到处进行类型转换。
  • 这种方法是从EntityManager得到Session,和SessionFactory.getCurrentSession()一样吗?我的意思是,如果它尚未创建,它会打开新的Session 吗?它在多线程环境中如何工作?
【解决方案2】:

SessionFactoryEntityManagerFactory

正如我在Hibernate User Guide 中解释的那样,Hibernate SessionFactory 扩展了 JPA EntityManagerFactory,如下图所示:

所以,SessionFactory 也是 JPA EntityManagerFactory

SessionFactoryEntityManagerFactory 都包含实体映射元数据,并允许您创建 Hibernate SessionEntityManager

SessionEntityManager

就像SessionFactoryEntityManagerFactory 一样,Hibernate Session 扩展了 JPA EntityManager。所以,EntityManager 定义的所有方法都可以在 Hibernate Session 中使用。

Session 和 `EntityManager 将 entity state transitions 转换为 SQL 语句,例如 SELECT、INSERT、UPDATE 和 DELETE。

Hibernate 与 JPA 引导程序

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

  1. 您可以通过 Hibernate 原生机制进行引导,并通过 BootstrapServiceRegistryBuilder 创建一个 SessionFactory。如果您使用的是 Spring,Hibernate 引导是通过 LocalSessionFactoryBean 完成的,如 this GitHub example 所示。
  2. 或者,您可以通过Persistence 类或EntityManagerFactoryBuilder 创建一个JPA EntityManagerFactory。如果您使用 Spring,JPA 引导是通过 LocalContainerEntityManagerFactoryBean 完成的,如 this GitHub example 所示。

首选通过 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 引导,使用 EntityManagerFactoryEntityManager,并且仅当您想要访问 JPA 中不可用的某些特定于 Hibernate 的方法时,才将它们解包到它们关联的 Hibernate 接口,例如通过其natural identifier 获取实体。

【讨论】:

    【解决方案3】:

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

    例如:

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

    【讨论】:

    • 请注意,根据 java 文档:javaee 6javaee 7unwrap() 优于 getDelegate()
    【解决方案4】:

    我更喜欢 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()
    • 您是如何直接获得 entityManager 的,并且表明您必须使用 sessionfactory 来获取会话。:D
    【解决方案5】:

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

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

    相关的 Hibernate 文档可以在 herehere 找到。

    Related SOF QuestionSpring Forum discussion

    【讨论】:

      【解决方案6】:

      通过使用 EntityManager,代码不再与休眠紧密耦合。但是为此,在使用中我们应该使用:

      javax.persistence.EntityManager
      

      而不是

      org.hibernate.ejb.HibernateEntityManager
      

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

      【讨论】:

        【解决方案7】:

        EntityManagerFactory 是标准实现,在所有实现中都是相同的。如果您为任何其他提供商(如 EclipseLink)迁移 ORM,则处理事务的方法不会发生任何变化。相反,如果您使用 hibernate 的会话工厂,它会绑定到 hibernate API,并且无法迁移到新的供应商。

        【讨论】:

          【解决方案8】:

          EntityManager 接口类似于 hibernate 中的 sessionFactory。 javax.persistance包下的EntityManager,org.hibernate.Session/sessionFactory包下的session和sessionFactory。

          实体管理器是 JPA 特定的,而 session/sessionFactory 是休眠特定的。

          【讨论】:

          • 您的答案是正确的,但与 Sangyun Lee 在他的 cmets 中所指的答案基本相同......所以重复。
          猜你喜欢
          • 1970-01-01
          • 2023-03-21
          • 2019-06-14
          • 2021-06-29
          • 2021-08-30
          • 2015-05-19
          • 2012-03-08
          • 2013-07-28
          相关资源
          最近更新 更多