Entitymanagerfactory 和 Sessionfactory
1、简介
本文将带你了解 SessionFactory
和 EntityManagerFactory
之间的异同。
顾名思义,这两个类都是用于创建数据库通信对象的工厂类。除了创建对象,它们还提供了其他功能,帮助我们与数据库进行交互。
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
实例外,还有其他相似之处:
- 两者都通过
CriteriaBuilder
和HibernateCriteriaBuilder
提供了辅助查询功能。 - 它们都支持事务,以保证数据的完整性。
- 必须要合理地管理它们,因为它们是资源密集型的,因此最好只将它们实例化一次,并重复使用该实例。
- 它们采用线程安全设计,允许并发访问。
如果我们看一下它们的实现,就会发现事实上,SessionFactory
继承了 EntityManagerFactory
。不过,两者之间也有一些关键区别。主要区别在于,SessionFactory
是 Hibernate 特有的概念,而 EntityManagerFactory
则是标准的 JPA 接口。
另一个重要区别是,Hibernate 支持二级缓存。它在 SessionFactory
级别运行,允许在所有 Session
中共享缓存数据。这项功能是 Hibernate 特有的,而 JPA 规范中并没有这项功能。
4.2、用例对比
在构建需要独 立于供应商(Vendor-Independent) 的应用时,应使用 EntityManagerFactory
,换句话说,我们可以轻松地交换底层实现(Hibernate、EclipseLink、OpenJpa 等)。如果需要使用 Hibernate 或其某些特定功能,如二级缓存和批量查询,则应使用 SessionFactory
。
总之,EntityManagerFactory
在不同的 JPA 实现中更具灵活性和可移植性,而 SessionFactory
则与 Hibernate 紧密耦合。
为了更好地理解,可以参考下表:
比较方面 | EntityManagerFactory | SessionFactory |
---|---|---|
规范 | JPA 规范的一部分 | Hibernate 专用 |
缓存 | 支持一级缓存 | 支持一级和二级缓存 |
查询语言 | 使用 JPQL(Java 持久化查询语言) | 可同时使用 JPQL 和 HQL(Hibernate 查询语言),因此查询更加灵活 |
灵活性 | 它与实现无关,这意味着它可与任何符合 JPA 标准的框架配合使用 | 仅在 Hibernate 中运行 |
应用场景 | 对灵活性有要求 | 需要使用 Hibernate 的特定功能 |
5、总结
本文介绍了 EntityManagerFactory
和 SessionFactory
的设置和使用,这两者的主要目的都是为数据库通信创建 Session
对象。很明显,SessionFactory
是 Hibernate 对标准 EntityManagerFactory
的特定适配。
在需要 Hibernate 特定功能的情况下,使用 SessionFactory
是个不错的选择。不过,如果要使用更标准化的方法,应该倾向于使用 JPA 规范,这意味着 EntityManagerFactory
是一个更好的选择。
Ref:https://www.baeldung.com/java-entitymanagerfactory-vs-sessionfactory