Entitymanagerfactory 和 Sessionfactory

1、简介

本文将带你了解 SessionFactoryEntityManagerFactory 之间的异同。

顾名思义,这两个类都是用于创建数据库通信对象的工厂类。除了创建对象,它们还提供了其他功能,帮助我们与数据库进行交互。

2、EntityManagerFactory 是什么?

Java 持久化 API(JPA)是 Java 应用管理持久化数据的规范。它提供了一种与关系数据库交互的标准方式。EntityManager(实体管理器)作为 JPA 的核心接口,用于与持久化上下文交互并管理实体的生命周期。它为基本的 CRUD 操作提供了具有方法的轻量级实例。

EntityManagerFactory 是一个 JPA 接口,用于创建 EntityManager 实例,以线程安全的方式与持久化上下文(Persistence Context)交互。

2.1、示例

首先,先定义实体:

@Entity(name = "persons")
public class Person {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String email;

    // Getter / Setter 省略
}

设置配置有多种方法,这里使用 persistence.xml 配置文件的方法。首先,需要在 resource/META-INF 文件夹中创建该配置文件,并定义连接配置:

<persistence-unit name="com.baeldung.sfvsemf.persistence_unit" transaction-type="RESOURCE_LOCAL">
    <description>Persistence Unit for SessionFactory vs EntityManagerFactory code example</description>
    <class>com.baeldung.sfvsemf.entity.Person</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.generate_statistics" value="false"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
        <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
        <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:db2;DB_CLOSE_DELAY=-1"/>
        <property name="jakarta.persistence.jdbc.user" value="sa"/>
        <property name="jakarta.persistence.jdbc.password" value=""/>
    </properties>
</persistence-unit>

注意,为简单起见,我们在本例中使用的是 H2 内存数据库,但并不局限于此。大多数关系数据库的工作方式相同,只需确保使用了正确的方言和驱动类。

2.2、使用

配置完成后,使用 EntityManagerFactory 创建 EntityManager 对象的过程就很简单了。

如果操作不当,使用 EntityManagerFactory 可能会有风险,因为它的创建成本很高。换句话说,EntityManagerFactory 的实例化需要大量资源,因此建议将其创建为单例类。

这里不会介绍详细的使用方法,只通过一个简单的示例代码来介绍基本操作。

如下:

@Test
public void givenEntityManagerFactory_whenPersistAndFind_thenAssertObjectPersisted() {
    // 实例化 EntityManagerFactory
    EntityManagerFactory entityManagerFactory =
      Persistence.createEntityManagerFactory("com.baeldung.sfvsemf.persistence_unit");

    // 创建一个 EntityManager 对象,然后使用它进行简单的数据库操作
    EntityManager entityManager = entityManagerFactory.createEntityManager();

    try {
        entityManager.getTransaction().begin();
        Person person = new Person("John", "johndoe@email.com");
        entityManager.persist(person);
        entityManager.getTransaction().commit();

        Person persistedPerson = entityManager.find(Person.class, person.getId());
        assertEquals(person.getName(), persistedPerson.getName());
        assertEquals(person.getEmail(), persistedPerson.getEmail());
    } catch (Exception ex) {
        entityManager.getTransaction().rollback();
    } finally {
        entityManager.close();
        entityManagerFactory.close();
    }
}

3、SessionFactory 是什么?

流行的 ORM 框架 Hibernate 使用 SessionFactory 作为创建和管理 Session 实例的工厂类。与 EntityManagerFactory 一样,SessionFactory 也提供了一种线程安全的方式来处理数据库连接和 CRUD 操作。

相比之下,Session 与实 EntityManager(体管理器)类似,因为它会与数据库交互、管理事务并处理实体的整个生命周期。

3.1、示例

在开始之前,我们假设你已经掌握了配置和使用 Hibernate 的知识,因为本文不会进行深入讲解。如果没有,请参阅 Hibernate 官方文档,了解更多信息。

我们使用与上一个示例中相同的实体类来演示 SessionFactory

Hibernate 主要使用 hibernate.cfg.xml 文件进行配置,把它添加到资源目录中:

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:mem:db2;DB_CLOSE_DELAY=-1</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
        <mapping class="com.baeldung.sfvsemf.entity.Person"/>
    </session-factory>
</hibernate-configuration>

3.2、使用

在使用 SessionFactory 之前,有必要提一下,与 EntityManagerFactory 类似,创建 SessionFactory 的成本也很高。一般建议将其作为单例使用。

配置好 SessionFactory 后,来看看如何使用它创建 Session 实例并执行基本的数据库操作:

@Test
void givenSessionFactory_whenPersistAndFind_thenAssertObjectPersisted() {
    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction transaction = null;

    try {
        transaction = session.beginTransaction();

        Person person = new Person("John", "johndoe@email.com");
        session.persist(person);
        transaction.commit();

        Person persistedPerson = session.find(Person.class, person.getId());
        assertEquals(person.getName(), persistedPerson.getName());
        assertEquals(person.getEmail(), persistedPerson.getEmail());
    } catch (Exception ex) {
        if (transaction != null) {
            transaction.rollback();
        }
    } finally {
        session.close();
        sessionFactory.close();
    }
}

4、EntityManagerFactory 和 SessionFactory 的对比

这两个工厂类有一些相似之处,并具有相同的目的。它们的主要作用是为数据库通信提供实例。

4.1、主要的差异

除了负责创建 Session 实例外,还有其他相似之处:

  • 两者都通过 CriteriaBuilderHibernateCriteriaBuilder 提供了辅助查询功能。
  • 它们都支持事务,以保证数据的完整性。
  • 必须要合理地管理它们,因为它们是资源密集型的,因此最好只将它们实例化一次,并重复使用该实例。
  • 它们采用线程安全设计,允许并发访问。

如果我们看一下它们的实现,就会发现事实上,SessionFactory 继承了 EntityManagerFactory。不过,两者之间也有一些关键区别。主要区别在于,SessionFactory 是 Hibernate 特有的概念,而 EntityManagerFactory 则是标准的 JPA 接口。

另一个重要区别是,Hibernate 支持二级缓存。它在 SessionFactory 级别运行,允许在所有 Session 中共享缓存数据。这项功能是 Hibernate 特有的,而 JPA 规范中并没有这项功能。

4.2、用例对比

在构建需要独 立于供应商(Vendor-Independent) 的应用时,应使用 EntityManagerFactory,换句话说,我们可以轻松地交换底层实现(HibernateEclipseLinkOpenJpa 等)。如果需要使用 Hibernate 或其某些特定功能,如二级缓存和批量查询,则应使用 SessionFactory

总之,EntityManagerFactory 在不同的 JPA 实现中更具灵活性和可移植性,而 SessionFactory 则与 Hibernate 紧密耦合。

为了更好地理解,可以参考下表:

比较方面 EntityManagerFactory SessionFactory
规范 JPA 规范的一部分 Hibernate 专用
缓存 支持一级缓存 支持一级和二级缓存
查询语言 使用 JPQL(Java 持久化查询语言) 可同时使用 JPQL 和 HQL(Hibernate 查询语言),因此查询更加灵活
灵活性 它与实现无关,这意味着它可与任何符合 JPA 标准的框架配合使用 仅在 Hibernate 中运行
应用场景 对灵活性有要求 需要使用 Hibernate 的特定功能

5、总结

本文介绍了 EntityManagerFactorySessionFactory 的设置和使用,这两者的主要目的都是为数据库通信创建 Session 对象。很明显,SessionFactoryHibernate 对标准 EntityManagerFactory 的特定适配。

在需要 Hibernate 特定功能的情况下,使用 SessionFactory 是个不错的选择。不过,如果要使用更标准化的方法,应该倾向于使用 JPA 规范,这意味着 EntityManagerFactory 是一个更好的选择。


Ref:https://www.baeldung.com/java-entitymanagerfactory-vs-sessionfactory