在本文中,我们探讨了EntityManagerFactory和SessionFactory的设置和使用。我们了解到,两者的主要用途都是为数据库通信创建会话对象。很明显,SessionFactory是 Hibernate 对标准EntityManagerFactory的特定改编。
如果我们需要 Hibernate 功能,那么使用SessionFactory是个不错的选择。但是,为了获得更标准化的方法,我们应该倾向于 JPA 规范,这意味着EntityManagerFactory是更好的选择。
在以下章节中,我们将研究这两个工厂类之间的区别,以便更好地理解何时使用它们。
什么是EntityManagerFactory?
Java持久性 API (JPA)是用于管理 Java 应用程序中持久数据的规范。它提供了一种与关系数据库交互的标准方法。EntityManager作为JPA的核心接口,用于与持久性上下文交互并管理实体的生命周期。它提供了轻量级实例,其中包含用于基本CRUD操作的方法。
话虽如此,我们注意到我们经常需要EntityManager实例,而这正是EntityManagerFactory可以帮助我们的地方。EntityManagerFactory是一个 JPA 接口,它创建EntityManager的实例,从而能够以线程安全的方式与持久性上下文进行交互。
设置过程
首先,让我们先定义一个实体:
@Entity(name = "persons") public class Person { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) private Integer id; private String name; private String email; // omitted getters and setters }
|
有几种方法可以设置配置,我们将介绍使用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 内存数据库,但不限于此。大多数关系数据库的工作方式相同,我们只需确保使用正确的方言和驱动程序类。
使用示例
配置完成后,使用EntityManagerFactory创建EntityManager对象的过程很简单。
如果操作不当,使用EntityManagerFactory可能会有风险,因为创建它的成本很高。换句话说,EntityManagerFactory实例化需要大量资源,因此建议将其创建为Singleton 类。
虽然我们不会详细介绍用法,但我们会通过代码示例介绍基本操作。我们不会创建单例,而是实例化EntityManagerFactory, 创建 EntityManager对象,然后继续使用它进行简单的数据库操作。
让我们看看实际情况是怎样的:
@Test public void givenEntityManagerFactory_whenPersistAndFind_thenAssertObjectPersisted() { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("com.baeldung.sfvsemf.persistence_unit"); 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(); } }
|
什么是SessionFactory?
流行的ORM框架 Hibernate 使用SessionFactory作为其工厂类来创建和管理Session实例。与EntityManagerFactory一样,SessionFactory也提供了一种线程安全的方法来处理数据库连接和 CRUD 操作。
相比之下,Session与EntityManager类似, 因为它与数据库交互、管理事务并处理实体的完整生命周期。
设置过程
在继续设置过程之前,我们假设我们已经具备配置和使用 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>
|
使用示例
在使用SessionFactory之前,需要注意的是,与EntityManagerFactory类似,它的创建成本也很高。一般建议将它们用作单例实例。
配置完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(); } }
|
EntityManagerFactory 与 SessionFactory 的比较
这两个工厂有许多相似之处,并且具有相同的用途。它们的主要作用是提供数据库通信实例。我们应该探索其他相似之处、不同之处以及可以利用它们的用例场景。
主要相似点和不同点
除了创建会话实例的职责外,还有其他的相似之处:
- 两者都通过CriteriaBuilder和HibernateCriteriaBuilder提供补充查询功能。
- 它们支持交易,帮助我们维护数据完整性。
- 我们必须小心管理它们,因为它们是资源密集型的,因此最好实例化一次并重复使用该实例。
- 它们的线程安全设计允许并发访问。
如果我们查看它们的实现,我们会注意到SessionFactory实际上继承了EntityManagerFactory。但是,两者之间存在一些关键差异。主要差异在于SessionFactory是 Hibernate 特有的概念,而EntityManagerFactory是标准 JPA 接口。
另一个重要的区别是 Hibernate 支持二级缓存。 它在SessionFactory 级别运行,允许缓存的数据在所有会话之间共享。此功能特定于 Hibernate,在 JPA 规范中不可用。
用例比较
- EntityManagerFactory应该用于构建需要独立于供应商的应用程序,换句话说,我们可以轻松交换底层提供程序(Hibernate、EclipseLink、OpenJpa 等)。
- 如果我们更喜欢 Hibernate 或它的某些特定功能,例如二级缓存和批量查询,则应该使用SessionFactory。
总之,EntityManagerFactory在各种 JPA 实现中更加灵活和可移植,而SessionFactory与 Hibernate 紧密耦合。