EntityManagerFactory 與 SessionFactory
一、簡介
在本教學中,我們將探討SessionFactory和EntityManagerFactory之間的異同。
顧名思義,兩者都是工廠類,用於建立資料庫通訊物件。除了創建物件之外,它們還提供其他功能來幫助我們與資料庫互動。
在下面的部分中,我們將研究這兩個工廠類別之間的區別,以便我們可以更好地理解何時使用它們。
2.什麼是EntityManagerFactory ?
Java Persistence API (JPA)用作管理 Java 應用程式中的持久性資料的規格。它提供了與關係資料庫互動的標準方法。 EntityManager是 JPA 的核心接口,用於與持久化上下文互動並管理實體的生命週期。它為輕量級實例提供了基本 CRUD 操作的方法。
也就是說,我們注意到我們經常需要EntityManager實例,這就是EntityManagerFactory可以幫助我們的地方。 EntityManagerFactory是一個 JPA 接口,它會建立EntityManager的實例,從而能夠以執行緒安全的方式與持久性上下文進行互動。
2.1.設定過程
第一步,我們先定義一個實體:
@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檔案介紹方法。首先,我們需要在 resources/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實例化需要大量資源,因此,建議將它們建立為 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", "[email protected]");
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後,我們來看看如何使用它來建立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", "[email protected]");
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.主要相似點和不同點
除了創建會話實例的職責之外,還有其他相似之處:
- 兩者都透過
[CriteriaBuilder](https://jakarta.ee/specifications/platform/9/apidocs/jakarta/persistence/criteria/criteriabuilder)和[HibernateCriteriaBuilder](https://docs.jboss.org/hibernate/orm/6.6/javadocs/org/hibernate/query/criteria/HibernateCriteriaBuilder.html) . - 它們支援事務,幫助我們維護資料完整性。
- 我們必須小心管理它們,因為它們是資源密集型的,因此最好實例化它們一次並重複使用該實例。
- 它們的線程安全設計允許並發存取。
如果我們查看它們的實現,我們會注意到實際上SessionFactory繼承了EntityManagerFactory 。然而,兩者之間存在一些關鍵差異。主要差異在於SessionFactory是 Hibernate 特定的概念,而EntityManagerFactory是標準的 JPA 介面。
另一個重要的區別是Hibernate 支援二級快取。它在SessionFactory層級運行,允許在所有會話之間共享快取的資料。此功能特定於 Hibernate,在 JPA 規範中不可用。
4.2.用例比較
當建置需要獨立於供應商的應用程式時應該使用EntityManagerFactory ,換句話說,我們可以輕鬆地交換底層提供者(Hibernate、EclipseLink、OpenJpa 等)。如果我們喜歡 Hibernate 或其某些特定功能,例如二級快取和批次查詢,我們應該使用SessionFactory 。
總之, EntityManagerFactory在各種 JPA 實作中往往更靈活且可移植,而SessionFactory則與 Hibernate 緊密耦合。
為了更好地理解,讓我們進行並排比較。
| 方面 | EntityManagerFactory |
SessionFactory |
|---|---|---|
| 標準化 | JPA 規範的一部分 | 特定於休眠 |
| 快取 | 支援一級緩存 | 支援一級、二級緩存 |
| 查詢語言 | 使用 JPQL(Java 持久性查詢語言) | 可以同時使用 JPQL 和 HQL(Hibernate 查詢語言),從而在查詢中提供更大的彈性 |
| 靈活性 | 它與供應商無關,這意味著它可以與任何符合 JPA 的框架一起使用 | 僅在 Hibernate 中工作 |
| 使用案例 | 當靈活性很重要時 | 我們可以在哪裡利用 Hibernate 的功能 |
5. 結論
在本文中,我們探討了EntityManagerFactory和SessionFactory的設定和使用。我們了解到,兩者都服務於為資料庫通訊創建會話物件的基本目的。很明顯, SessionFactory是 Hibernate 對標準EntityManagerFactory的特定改編。
如果我們需要 Hibernate 功能,那麼使用SessionFactory是一個不錯的選擇。然而,對於更標準化的方法,我們應該傾向於 JPA 規範,這意味著EntityManagerFactory是更好的選擇。
與往常一樣,完整的程式碼範例可以在 GitHub 上找到。