在 Java 中建立 Hibernate SessionFactory 時設定資料來源
1. 概述
在現代 Java 應用程式中, Hibernate很少自行管理資料庫連線。相反,應用程式依賴Datasource來進行連線池管理、生命週期管理以及確保效能穩定。這個模型與 Spring Boot 非常契合,因為 Spring Boot 的基礎架構元件通常是自動配置並由外部團隊管理的。
然而,在某些情況下,我們需要明確控制SessionFactory 的建立方式以及它如何使用Datasource 。這種情況通常出現在自訂 Hibernate 引導程式、使用多個資料庫或在標準 JPA 設定之外整合 Hibernate 時。
本文中,我們將 Hibernate 設定為原生模式,並讓 Spring Boot 只處理Datasource和應用程式生命週期。為了避免基礎架構重疊,我們將停用 JPA 和 Spring Data JPA 的自動設定。我們將逐步介紹核心概念、設定選項,並提供包含 JUnit 測試的完整 Spring Boot 範例。
2. SessionFactory 和資料來源背後的核心概念
在深入探討 Spring Boot 設定之前,我們必須先先明確 Hibernate 和 Spring 的職責劃分。從宏觀層面來看,Spring 管理諸如Datasource之類的基礎架構元件,而 Hibernate 則專注於 ORM 相關事宜以及透過SessionFactory:
此圖展示了 Spring Boot 中 Hibernate 的會話管理流程,從應用程式啟動開始,透過分層元件實現高效的資料庫存取。這種流程確保了諸如SessionFactory等重量級組件的正確初始化,同時實現了輕量級的按需會話。
2.1. SessionFactory在 Hibernate 中的作用
SessionFactory是 Hibernate 的主要入口點。它儲存配置元資料並建立用於與資料庫互動的Session實例。由於創建 SessionFactory 的開銷較大,我們只在啟動時初始化一次,然後在整個應用程式中重複使用。
當我們選擇不啟用 JPA 自動配置時,Hibernate 將不再為我們建置此元件。因此,我們必須明確地配置SessionFactory並提供所有必需的依賴項,包括Datasource 。
2.2. 為什麼Datasource很重要?
Datasource封裝了 JDBC 連線管理,通常提供連線池。 Hibernate 依賴資料來源來獲取連接,而不是直接管理連接,這提高了穩定性和可擴展性。
Spring Boot 將Datasource作為託管 bean 公開。一旦可用,Hibernate 即可直接使用它,無論應用程式是使用自動配置還是完全手動配置。
3. Spring Boot 中的資料來源處理
如果資料庫屬性存在,Spring Boot 會自動建立Datasource 。我們真正控制的是 Hibernate 在建構SessionFactory時如何使用該Datasource 。
3.1. 預設行為與手動配置
預設情況下,Spring Boot 會使用spring.jpa屬性自動配置 Hibernate 並自動連接Datasource 。這對於大多數應用程式來說都適用。
然而,當我們想要完全控制 Hibernate 的啟動過程時,我們可以定義自己的SessionFactory bean 並明確注入Datasource 。這樣我們就可以透過程式控制 Hibernate 的屬性和啟動行為。以下是一個注入Datasource的最小範例:
@Bean
SessionFactory sessionFactory(DataSource dataSource) {
StandardServiceRegistry registry =
new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.datasource",dataSource)
.build();
Metadata metadata =
new MetadataSources(registry).buildMetadata();
return metadata.buildSessionFactory();
}
在這裡,我們將 Spring 管理的Datasource明確注入到 Hibernate 的SessionFactory 。透過自行定義這個 bean,我們繞過了 Spring Boot 的 JPA 驅動的配置,完全掌控了 Hibernate 的初始化方式,同時仍受益於 Spring 的連接管理功能。
3.2. 限制 JPA 自動配置
Spring Boot 會自動啟用 JPA 基礎架構,包括建立EntityManagerFactory和相關 bean。
由於本文重點介紹 Hibernate 的原生用法,因此必須明確停用 JPA 自動設定。這樣做可以防止 Spring 建立未使用的基礎架構,並避免啟動期間的衝突。
4. Spring Boot 設定範例
讓我們透過一個完整的基於 Spring Boot 的範例來了解在建立 Hibernate SessionFactory時如何明確地設定Datasource 。
4.1. Maven 依賴項
我們將使用[spring-boot-starter-jdbc](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc) , [hibernate-core](https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core) , [H2](https://mvnrepository.com/artifact/com.h2database/h2/2.2.224) ,和[JUnit](https://mvnrepository.com/artifact/junit/junit) .以下版本穩定且常用:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.4.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.2.4</version>
<scope>test</scope>
</dependency>
目前,我們刻意避免使用Spring Data JPA ,而僅依賴spring-boot-starter-jdbc建立Datasource 。這種配置提供了啟動 Hibernate、配置Datasource以及執行整合測試所需的一切。
4.2 應用程式屬性
Spring Boot 根據標準配置屬性建立Datasource :
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
然而,在這種配置下,我們無需明確定義上述Datasource配置。 Spring Boot 仍然會自動建立一個記憶體中的 H2 資料庫,並為 Hibernate 提供可用的Datasource 。此處列出的屬性僅用於強調這一差異。
由於 JPA 自動配置已停用,因此spring.jpa.hibernate.ddl-auto和spring.jpa.show-sql等 JPA 特有的屬性將被忽略,並且等效行為將透過編程方式進行配置。
4.3. 停用 JPA 基礎架構
在定義 Hibernate SessionFactory之前,我們將停用 JPA 和 Spring Data JPA 的自動設定。這可以確保 Spring Boot 不會嘗試建立EntityManagerFactory或相關的 JPA 基礎架構 bean:
@SpringBootApplication(
exclude = {
HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class
}
)
public class HibernateSessionFactoryDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HibernateSessionFactoryDemoApplication.class, args);
}
}
此配置保留了 Spring Boot 的datasource自動配置功能,同時阻止了 JPA 特定 bean 的初始化。因此,Hibernate 以原生模式運行,並且完全依賴明確配置的 SessionFactory。
4.4. 明確 SessionFactory 配置
現在我們將定義一個配置類,該類使用 Spring 管理的資料來源建立 Hibernate SessionFactory Datasource:
@Configuration
public class HibernateConfig {
@Bean
SessionFactory sessionFactory(DataSource dataSource) {
StandardServiceRegistry registry =
new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.datasource", dataSource)
.applySetting("hibernate.hbm2ddl.auto", "create-drop")
.applySetting("hibernate.show_sql", true)
.build();
MetadataSources sources = new MetadataSources(registry);
return sources.buildMetadata().buildSessionFactory();
}
}
在此配置中,Spring會自動注入Datasource bean 。然後,我們使用hibernate.connection.datasource設定將該Datasource傳遞給 Hibernate。從Hibernate 6開始,SQL 方言會自動從 JDBC 連線元資料中偵測出來,不再需要明確設定方言。這確保所有資料庫連線都來自 Spring 的連線池。
5. 使用 JUnit 驗證配置
為了確保一切能如預期運行,我們將編寫一個 Spring Boot 測試,以驗證SessionFactory是否可以開啟 Hibernate Session :
@SpringBootTest
public class SessionFactoryUnitTest {
@Autowired
private SessionFactory sessionFactory;
@Test
void givenSessionFactory_whenOpeningSession_thenSessionIsCreated() {
try (Session session = sessionFactory.openSession()) {
assertNotNull(session);
}
}
}
此測試啟動 Spring 上下文,載入自訂的SessionFactory bean,並驗證 Hibernate 是否能夠透過配置的Datasource成功取得資料庫連線。如果配置錯誤,此測試會在上下文初始化或會話建立期間提前失敗。
此測試成功,因為 JPA 基礎架構已被明確停用。 Spring Boot 會載入應用程式上下文,提供Datasource ,並注入自訂的 Hibernate SessionFactory ,而不會嘗試建立EntityManagerFactory 。這證實 Hibernate 以原生模式運行,同時仍受益於 Spring Boot 的生命週期和組態管理。
6. 使用場景和設計考慮因素
這種顯式配置方式在我們需要更嚴格地控制 Hibernate 的初始化方式以及它與基礎設施的連接方式時非常有用。雖然 Spring Boot 的預設設定可以涵蓋大多數用例,但在某些特定場景下,明確定義這些關係會更有優勢。
我們通常在自訂 Hibernate 行為、處理多個datasources或使 Hibernate 啟動與其他系統元件保持一致時應用此方法:
| 設想 | 首選配置樣式 | 為什麼這種方法行之有效 |
|---|---|---|
| 簡單的 CRUD 應用 | Spring Boot JPA 自動配置 | 最大程度簡化設定並隱藏 Hibernate 內部細節 |
| 自訂 Hibernate 行為 | 顯式SessionFactory配置 | 提供精細控制 |
| 多個資料來源 | 程式化 Hibernate 設定 | 避免跨資料庫耦合 |
| 啟動或連接調試 | 手動配置 | 使依賴關係可見 |
| 用例 | 一般 | 金融、科學 |
7. 結論
一旦了解 Spring Boot 和 Hibernate 的互動方式,在 Java 中建立 Hibernate SessionFactory時設定Datasource就變得非常簡單。透過讓 Spring 管理Datasource並將其明確地連接到 Hibernate,我們可以在不犧牲穩定性的前提下,獲得清晰性、控制力和靈活性。
本文探討了SessionFactory和Datasource的核心概念,分析了 Spring Boot 如何管理資料庫連接,並實現了一個包含整合測試的完整配置。透過停用 JPA 自動配置並將Datasource直接整合到 Hibernate 中,我們避免了框架的隱藏行為,確保應用程式完全使用我們配置的持久化基礎架構。
這種方法能夠很好地從簡單的應用程式擴展到更複雜的架構,讓我們確信 Hibernate 使用的是我們預期的連接設定。和往常一樣,此範例的程式碼已發佈在 GitHub 上。