組態

本節說明如何透過以下方式設定 Spring Data JPA:

基於註解的組態

Spring Data JPA 儲存庫支援可以透過 JavaConfig 以及自訂 XML 命名空間來啟用,如下列範例所示

範例 1. 使用 JavaConfig 的 Spring Data JPA 儲存庫
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
class ApplicationConfig {

  @Bean
  public DataSource dataSource() {

    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder.setType(EmbeddedDatabaseType.HSQL).build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.acme.domain");
    factory.setDataSource(dataSource());
    return factory;
  }

  @Bean
  public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory);
    return txManager;
  }
}
您必須建立 LocalContainerEntityManagerFactoryBean 而非直接建立 EntityManagerFactory,因為前者除了建立 EntityManagerFactory 外,還參與例外轉換機制。

先前的組態類別透過使用 spring-jdbcEmbeddedDatabaseBuilder API 來設定嵌入式 HSQL 資料庫。然後 Spring Data 設定 EntityManagerFactory 並使用 Hibernate 作為範例持久化提供者。此處宣告的最後一個基礎架構元件是 JpaTransactionManager。最後,此範例透過使用 @EnableJpaRepositories 註解來啟用 Spring Data JPA 儲存庫,其本質上與 XML 命名空間具有相同的屬性。如果未組態基本套件,則會使用組態類別所在的套件。

Spring 命名空間

Spring Data 的 JPA 模組包含一個自訂命名空間,允許定義儲存庫 bean。它還包含某些 JPA 特有的功能和元素屬性。一般而言,可以使用 repositories 元素來設定 JPA 儲存庫,如下列範例所示

範例 2. 使用命名空間設定 JPA 儲存庫
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <jpa:repositories base-package="com.acme.repositories" />

</beans>
JavaConfig 或 XML 哪個更好?XML 是 Spring 很久以前的組態方式。在當今 Java 快速成長的時代,記錄類型、註解等等,新專案通常會盡可能使用純 Java。雖然目前沒有立即移除 XML 支援的計畫,但某些最新功能可能無法透過 XML 使用。

使用 repositories 元素,它會為所有使用 @Repository 註解的 bean 啟動持久化例外轉換,以讓 JPA 持久化提供者擲回的例外轉換為 Spring 的 DataAccessException 階層。

自訂命名空間屬性

除了 repositories 元素的預設屬性外,JPA 命名空間還提供額外的屬性,讓您可以更詳細地控制儲存庫的設定

表 1. repositories 元素的自訂 JPA 特定屬性

entity-manager-factory-ref

明確地將 EntityManagerFactory 連接到要與 repositories 元素偵測到的儲存庫一起使用。通常在應用程式中使用多個 EntityManagerFactory bean 時使用。如果未組態,Spring Data 會自動在 ApplicationContext 中查閱名稱為 entityManagerFactoryEntityManagerFactory bean。

transaction-manager-ref

明確地將 PlatformTransactionManager 連接到要與 repositories 元素偵測到的儲存庫一起使用。通常僅在組態了多個交易管理器或 EntityManagerFactory bean 時才需要。預設為目前 ApplicationContext 內定義的單個 PlatformTransactionManager

如果未定義明確的 transaction-manager-ref,Spring Data JPA 需要一個名為 transactionManagerPlatformTransactionManager bean。

啟動模式

預設情況下,Spring Data JPA 儲存庫是預設的 Spring bean。它們是 singleton 作用域且急切初始化。在啟動期間,它們已經與 JPA EntityManager 互動,以進行驗證和中繼資料分析。Spring Framework 支援在背景執行緒中初始化 JPA EntityManagerFactory,因為此程序通常會在 Spring 應用程式中佔用大量的啟動時間。為了有效地利用背景初始化,我們需要確保盡可能延遲 JPA 儲存庫的初始化。

從 Spring Data JPA 2.1 開始,您現在可以組態 BootstrapMode(透過 @EnableJpaRepositories 註解或 XML 命名空間),它採用以下值

  • DEFAULT(預設)— 除非明確使用 @Lazy 註解,否則儲存庫會急切地實例化。如果沒有用戶端 bean 需要儲存庫的實例,則延遲化才會生效,因為這將需要初始化儲存庫 bean。

  • LAZY — 隱含地將所有儲存庫 bean 宣告為延遲,並導致建立延遲初始化代理以注入到用戶端 bean 中。這表示,如果用戶端 bean 只是將實例儲存在欄位中,而未在初始化期間使用儲存庫,則儲存庫將不會被實例化。儲存庫實例將在首次與儲存庫互動時初始化和驗證。

  • DEFERRED — 在操作模式上與 LAZY 基本相同,但在回應 ContextRefreshedEvent 時觸發儲存庫初始化,以便在應用程式完全啟動之前驗證儲存庫。

建議

如果您未使用非同步 JPA 啟動,請堅持使用預設啟動模式。

如果您非同步啟動 JPA,DEFERRED 是一個合理的預設值,因為它可以確保 Spring Data JPA 啟動僅在 EntityManagerFactory 設定本身花費的時間比初始化所有其他應用程式元件更長時,才會等待 EntityManagerFactory 設定。儘管如此,它仍然確保在應用程式發出訊號表示已啟動之前,儲存庫已正確初始化和驗證。

LAZY 是測試情境和本機開發的理想選擇。一旦您非常確定儲存庫可以正確啟動,或者在您測試應用程式的其他部分的情況下,為所有儲存庫執行驗證可能會不必要地增加啟動時間。這也適用於本機開發,在這種開發中,您僅存取可能需要初始化單個儲存庫的應用程式部分。