資料訪問

Spring Boot 包含許多用於處理資料來源的啟動器。本節回答與此相關的問題。

配置自定義 DataSource

要配置您自己的 DataSource,請在您的配置中定義一個該型別的 @Bean。Spring Boot 會在任何需要的地方複用您的 DataSource,包括資料庫初始化。如果您需要將某些設定外部化,您可以將您的 DataSource 繫結到環境(參見 第三方配置)。

以下示例展示瞭如何在 Bean 中定義資料來源

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	public SomeDataSource dataSource() {
		return new SomeDataSource();
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	fun dataSource(): SomeDataSource {
		return SomeDataSource()
	}

}

以下示例展示瞭如何透過設定屬性來定義資料來源

  • 屬性

  • YAML

app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30
app:
  datasource:
    url: "jdbc:h2:mem:mydb"
    username: "sa"
    pool-size: 30

假設 SomeDataSource 具有用於 URL、使用者名稱和連線池大小的常規 JavaBean 屬性,這些設定會在 DataSource 可用於其他元件之前自動繫結。

Spring Boot 還提供了一個名為 DataSourceBuilder 的實用構建器類,可用於建立標準資料來源之一(如果它在 classpath 中)。構建器可以根據 classpath 中可用的內容檢測要使用哪一個。它還會根據 JDBC URL 自動檢測驅動程式。

以下示例展示瞭如何使用 DataSourceBuilder 建立資料來源

  • Java

  • Kotlin

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}

}
import javax.sql.DataSource

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	fun dataSource(): DataSource {
		return DataSourceBuilder.create().build()
	}

}

要使用該 DataSource 執行應用程式,您所需要的只是連線資訊。還可以提供特定於連線池的設定。請檢查執行時將使用的實現以獲取更多詳細資訊。

以下示例展示瞭如何透過設定屬性來定義 JDBC 資料來源

  • 屬性

  • YAML

app.datasource.url=jdbc:mysql:///test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
  datasource:
    url: "jdbc:mysql:///test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

然而,由於方法的 DataSource 返回型別,存在一個問題。這會隱藏連線池的實際型別,因此不會為您的自定義 DataSource 生成任何配置屬性元資料,並且您的 IDE 中沒有自動完成功能。為了解決此問題,請使用構建器的 type(Class) 方法指定要構建的 DataSource 型別並更新方法的返回型別。例如,以下示例展示瞭如何使用 DataSourceBuilder 建立 HikariDataSource

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	public HikariDataSource dataSource() {
		return DataSourceBuilder.create().type(HikariDataSource.class).build();
	}

}
import com.zaxxer.hikari.HikariDataSource
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

	@Bean
	@ConfigurationProperties("app.datasource")
	fun dataSource(): HikariDataSource {
		return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
	}

}

不幸的是,這個基本設定不起作用,因為 Hikari 沒有 url 屬性。相反,它有一個 jdbc-url 屬性,這意味著您必須將配置重寫如下

  • 屬性

  • YAML

app.datasource.jdbc-url=jdbc:mysql:///test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
  datasource:
    jdbc-url: "jdbc:mysql:///test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

為了解決這個問題,請使用 DataSourceProperties,它將為您處理 urljdbc-url 的轉換。您可以使用其 initializeDataSourceBuilder() 方法從任何 DataSourceProperties 物件的狀態初始化 DataSourceBuilder。您可以注入 Spring Boot 自動建立的 DataSourceProperties,但是,這會將您的配置分散在 spring.datasource.*app.datasource.* 中。為了避免這種情況,請定義一個帶有自定義配置屬性字首的自定義 DataSourceProperties,如以下示例所示

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource")
	public DataSourceProperties dataSourceProperties() {
		return new DataSourceProperties();
	}

	@Bean
	@ConfigurationProperties("app.datasource.configuration")
	public HikariDataSource dataSource(DataSourceProperties properties) {
		return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

}
import com.zaxxer.hikari.HikariDataSource
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary

@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {

	@Bean
	@Primary
	@ConfigurationProperties("app.datasource")
	fun dataSourceProperties(): DataSourceProperties {
		return DataSourceProperties()
	}

	@Bean
	@ConfigurationProperties("app.datasource.configuration")
	fun dataSource(properties: DataSourceProperties): HikariDataSource {
		return properties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
	}

}

此設定等同於 Spring Boot 預設為您執行的操作,不同之處在於連線池的型別是在程式碼中指定的,並且其設定以 app.datasource.configuration.* 屬性的形式公開。DataSourceProperties 負責 urljdbc-url 的轉換,因此您可以按如下方式配置它

  • 屬性

  • YAML

app.datasource.url=jdbc:mysql:///test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
  datasource:
    url: "jdbc:mysql:///test"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30

請注意,由於自定義配置在程式碼中指定應使用 Hikari,因此 app.datasource.type 將不起作用。

支援的連線池 中所述,DataSourceBuilder 支援幾種不同的連線池。要使用 Hikari 以外的連線池,請將其新增到 classpath,使用 type(Class) 方法指定要使用的連線池類,並更新 @Bean 方法的返回型別以匹配。這還將為您選擇的特定連線池提供配置屬性元資料。

Spring Boot 會將 Hikari 特定的設定暴露給 spring.datasource.hikari。本示例使用更通用的 configuration 子名稱空間,因為該示例不支援多個數據源實現。

有關更多詳細資訊,請參閱 配置 DataSourceDataSourceAutoConfiguration 類。

配置兩個 DataSource

要定義一個額外的 DataSource,可以使用類似於上一節的方法。一個關鍵區別是,DataSource @Bean 必須宣告 defaultCandidate=false。這可以防止自動配置的 DataSource 回退。

Spring Framework 參考文件 更詳細地描述了此功能。

為了允許將額外的 DataSource 注入到需要它的地方,也用 @Qualifier 註解它,如以下示例所示

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyAdditionalDataSourceConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource")
	public HikariDataSource secondDataSource() {
		return DataSourceBuilder.create().type(HikariDataSource.class).build();
	}

}
import com.zaxxer.hikari.HikariDataSource

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.DataSourceBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyAdditionalDataSourceConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource")
	fun secondDataSource(): HikariDataSource {
		return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
	}

}

要使用額外的 DataSource,請使用相同的 @Qualifier 註解注入點。

自動配置和額外的資料來源可以按如下方式配置

  • 屬性

  • YAML

spring.datasource.url=jdbc:mysql:///first
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.configuration.maximum-pool-size=30
app.datasource.url=jdbc:mysql:///second
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.max-total=30
spring:
  datasource:
    url: "jdbc:mysql:///first"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30
app:
  datasource:
    url: "jdbc:mysql:///second"
    username: "dbuser"
    password: "dbpass"
    max-total: 30

透過 spring.datasource.configuration.* 屬性,可以對自動配置的 DataSource 進行更高階、特定於實現的配置。您也可以將相同的概念應用於額外 DataSource,如以下示例所示

  • Java

  • Kotlin

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCompleteAdditionalDataSourceConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource")
	public DataSourceProperties secondDataSourceProperties() {
		return new DataSourceProperties();
	}

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource.configuration")
	public HikariDataSource secondDataSource(
			@Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
		return secondDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

}
import com.zaxxer.hikari.HikariDataSource

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyCompleteAdditionalDataSourceConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource")
	fun secondDataSourceProperties(): DataSourceProperties {
		return DataSourceProperties()
	}

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.datasource.configuration")
	fun secondDataSource(secondDataSourceProperties: DataSourceProperties): HikariDataSource {
		return secondDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
	}

}

前面的示例使用與 Spring Boot 在自動配置中使用的相同邏輯配置了額外的資料來源。請注意,app.datasource.configuration.* 屬性根據所選實現提供高階設定。

配置單個自定義 DataSource一樣,可以使用 DataSourceBuilder 上的 type(Class) 方法自定義一個或兩個 DataSource bean 的型別。有關支援型別的詳細資訊,請參閱 支援的連線池

使用 Spring Data Repository

Spring Data 可以建立各種風格的 Repository 介面實現。只要這些 Repository 實現包含在 自動配置包 之一中,Spring Boot 就會為您處理所有這些,通常是您的主應用程式類(用 @SpringBootApplication@EnableAutoConfiguration 註解)的包(或子包)。

對於許多應用程式,您所需要做的就是將正確的 Spring Data 依賴項放在您的 classpath 中。有用於 JPA 的 spring-boot-starter-data-jpa,用於 Mongodb 的 spring-boot-starter-data-mongodb,以及用於受支援技術的各種其他啟動器。要開始使用,請建立一些儲存庫介面來處理您的 @Entity 物件。

Spring Boot 透過掃描 自動配置包 來確定您的 Repository 實現的位置。為了進行更多控制,請使用 Spring Data 中的 @Enable…Repositories 註解。

有關 Spring Data 的更多資訊,請參閱 Spring Data 專案頁面

將 @Entity 定義與 Spring 配置分離

Spring Boot 透過掃描 自動配置包 來確定您的 @Entity 定義的位置。為了進行更多控制,請使用 @EntityScan 註解,如以下示例所示

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class MyApplication {

	// ...

}
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.persistence.autoconfigure.EntityScan
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = [City::class])
class MyApplication {

	// ...

}

過濾掃描到的 @Entity 定義

可以使用 ManagedClassNameFilter bean 過濾 @Entity 定義。這在測試中非常有用,此時只應考慮可用實體的一個子集。在以下示例中,只包含來自 com.example.app.customer 包的實體

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;

@Configuration(proxyBeanMethods = false)
public class MyEntityScanConfiguration {

	@Bean
	public ManagedClassNameFilter entityScanFilter() {
		return (className) -> className.startsWith("com.example.app.customer.");
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter

@Configuration(proxyBeanMethods = false)
class MyEntityScanConfiguration {

	@Bean
	fun entityScanFilter() : ManagedClassNameFilter {
		return ManagedClassNameFilter { className ->
			className.startsWith("com.example.app.customer.")
		}
	}
}

配置 JPA 屬性

Spring Data JPA 已經提供了一些與供應商無關的配置選項(例如用於 SQL 日誌記錄的選項),Spring Boot 將這些選項和一些 Hibernate 選項作為外部配置屬性暴露。其中一些會根據上下文自動檢測,因此您無需設定它們。

spring.jpa.hibernate.ddl-auto 是一個特殊情況,因為根據執行時條件,它有不同的預設值。如果使用嵌入式資料庫並且沒有模式管理器(如 Liquibase 或 Flyway)處理 DataSource,則預設為 create-drop。在所有其他情況下,預設為 none

要使用的方言由 JPA 提供程式檢測。如果您希望自行設定方言,請設定 spring.jpa.database-platform 屬性。

以下示例顯示了最常見的設定選項

  • 屬性

  • YAML

spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true
spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: "com.example.MyPhysicalNamingStrategy"
    show-sql: true

此外,在建立本地 EntityManagerFactory 時,spring.jpa.properties.* 中的所有屬性都作為常規 JPA 屬性(去除字首)傳遞。

您需要確保 spring.jpa.properties.* 下定義的名稱與您的 JPA 提供程式預期的名稱完全匹配。Spring Boot 不會嘗試對這些條目進行任何形式的寬鬆繫結。

例如,如果要配置 Hibernate 的批處理大小,則必須使用 spring.jpa.properties.hibernate.jdbc.batch_size。如果您使用其他形式,例如 batchSizebatch-size,Hibernate 將不會應用該設定。

如果您需要對 Hibernate 屬性進行高階自定義,請考慮註冊一個 HibernatePropertiesCustomizer bean,它將在建立 EntityManagerFactory 之前被呼叫。這優先於自動配置應用的任何內容。

配置 Hibernate 命名策略

Hibernate 使用 兩種不同的命名策略 將物件模型中的名稱對映到相應的資料庫名稱。物理和隱式策略實現的完全限定類名可以透過設定 spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy 屬性來配置。或者,如果應用程式上下文中存在 ImplicitNamingStrategyPhysicalNamingStrategy bean,Hibernate 將自動配置為使用它們。

預設情況下,Spring Boot 使用 CamelCaseToUnderscoresNamingStrategy 配置物理命名策略。使用此策略,所有點都替換為下劃線,駝峰命名法也替換為下劃線。此外,預設情況下,所有表名都以小寫生成。例如,TelephoneNumber 實體對映到 telephone_number 表。如果您的模式需要混合大小寫識別符號,請定義一個自定義 CamelCaseToUnderscoresNamingStrategy bean,如以下示例所示

  • Java

  • Kotlin

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {

	@Bean
	public PhysicalNamingStrategySnakeCaseImpl caseSensitivePhysicalNamingStrategy() {
		return new PhysicalNamingStrategySnakeCaseImpl() {

			@Override
			public Identifier toPhysicalColumnName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
				return logicalName;
			}

		};
	}

}
import org.hibernate.boot.model.naming.Identifier
import org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

	@Bean
	fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategySnakeCaseImpl {
		return object : PhysicalNamingStrategySnakeCaseImpl() {
			override fun toPhysicalColumnName(logicalName: Identifier, jdbcEnvironment: JdbcEnvironment): Identifier {
				return logicalName
			}
		}
	}

}

如果您更喜歡使用 Hibernate 的預設設定,請設定以下屬性

  • 屬性

  • YAML

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

或者,您可以配置以下 Bean

  • Java

  • Kotlin

import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

	@Bean
	PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {
		return new PhysicalNamingStrategyStandardImpl();
	}

}
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
internal class MyHibernateConfiguration {

	@Bean
	fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategyStandardImpl {
		return PhysicalNamingStrategyStandardImpl()
	}

}

有關更多詳細資訊,請參閱 HibernateJpaAutoConfigurationJpaBaseConfiguration

配置 Hibernate 二級快取

Hibernate 二級快取 可以為一系列快取提供程式配置。與其配置 Hibernate 再次查詢快取提供程式,不如儘可能提供上下文中可用的快取提供程式。

要使用 JCache 執行此操作,首先請確保 org.hibernate.orm:hibernate-jcache 在 classpath 中可用。然後,新增一個 HibernatePropertiesCustomizer bean,如以下示例所示

  • Java

  • Kotlin

import org.hibernate.cache.jcache.ConfigSettings;

import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {

	@Bean
	public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
		return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
	}

}
import org.hibernate.cache.jcache.ConfigSettings
import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer
import org.springframework.cache.jcache.JCacheCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyHibernateSecondLevelCacheConfiguration {

	@Bean
	fun hibernateSecondLevelCacheCustomizer(cacheManager: JCacheCacheManager): HibernatePropertiesCustomizer {
		return HibernatePropertiesCustomizer { properties ->
			val cacheManager = cacheManager.cacheManager
			if (cacheManager != null) {
				properties[ConfigSettings.CACHE_MANAGER] = cacheManager
			}
		}
	}

}

此定製器將配置 Hibernate 以使用應用程式使用的相同 CacheManager。也可以使用單獨的 CacheManager 例項。有關詳細資訊,請參閱 Hibernate 使用者指南

在 Hibernate 元件中使用依賴注入

預設情況下,Spring Boot 註冊一個使用 BeanFactoryBeanContainer 實現,以便轉換器和實體監聽器可以使用常規的依賴注入。

您可以透過註冊一個 HibernatePropertiesCustomizer 來停用或調整此行為,該定製器會刪除或更改 hibernate.resource.beans.container 屬性。

使用自定義 EntityManagerFactory

要完全控制 EntityManagerFactory 的配置,您需要新增一個名為“entityManagerFactory”的 @Bean。如果存在該型別的 bean,Spring Boot 自動配置將關閉其實體管理器。

當您自己為 LocalContainerEntityManagerFactoryBean 建立 bean 時,在建立自動配置的 LocalContainerEntityManagerFactoryBean 期間應用的任何自定義都將丟失。請務必使用自動配置的 EntityManagerFactoryBuilder 以保留 JPA 和供應商屬性。如果您依賴 spring.jpa.* 屬性來配置命名策略或 DDL 模式等內容,這一點尤為重要。

使用多個 EntityManagerFactories

如果您需要對多個數據源使用 JPA,您可能需要每個資料來源一個 EntityManagerFactory。Spring ORM 中的 LocalContainerEntityManagerFactoryBean 允許您為您的需求配置一個 EntityManagerFactory。您還可以重用 JpaProperties 來繫結第二個 EntityManagerFactory 的設定。在 配置第二個 DataSource 的示例的基礎上,可以定義第二個 EntityManagerFactory,如以下示例所示

  • Java

  • Kotlin

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.jpa.autoconfigure.JpaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

@Configuration(proxyBeanMethods = false)
public class MyAdditionalEntityManagerFactoryConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.jpa")
	public JpaProperties secondJpaProperties() {
		return new JpaProperties();
	}

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(@Qualifier("second") DataSource dataSource,
			@Qualifier("second") JpaProperties jpaProperties) {
		EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(jpaProperties);
		return builder.dataSource(dataSource).packages(Order.class).persistenceUnit("second").build();
	}

	private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
		JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
		Function<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> createJpaProperties(dataSource,
				jpaProperties.getProperties());
		return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null);
	}

	private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
		// ... map JPA properties as needed
		return new HibernateJpaVendorAdapter();
	}

	private Map<String, ?> createJpaProperties(DataSource dataSource, Map<String, ?> existingProperties) {
		Map<String, ?> jpaProperties = new LinkedHashMap<>(existingProperties);
		// ... map JPA properties that require the DataSource (e.g. DDL flags)
		return jpaProperties;
	}

}
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jpa.EntityManagerFactoryBuilder
import org.springframework.boot.jpa.autoconfigure.JpaProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.orm.jpa.JpaVendorAdapter
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
import javax.sql.DataSource

@Configuration(proxyBeanMethods = false)
class MyAdditionalEntityManagerFactoryConfiguration {

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	@ConfigurationProperties("app.jpa")
	fun secondJpaProperties(): JpaProperties {
		return JpaProperties()
	}

	@Qualifier("second")
	@Bean(defaultCandidate = false)
	fun firstEntityManagerFactory(
		@Qualifier("second") dataSource: DataSource,
		@Qualifier("second") jpaProperties: JpaProperties
	): LocalContainerEntityManagerFactoryBean {
		val builder = createEntityManagerFactoryBuilder(jpaProperties)
		return builder.dataSource(dataSource).packages(Order::class.java).persistenceUnit("second").build()
	}

	private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
		val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
		val jpaPropertiesFactory = { dataSource: DataSource ->
				createJpaProperties(dataSource, jpaProperties.properties) }
		return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null)
	}

	private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
		// ... map JPA properties as needed
		return HibernateJpaVendorAdapter()
	}

	private fun createJpaProperties(dataSource: DataSource, existingProperties: Map<String, *>): Map<String, *> {
		val jpaProperties: Map<String, *> = LinkedHashMap(existingProperties)
		// ... map JPA properties that require the DataSource (e.g. DDL flags)
		return jpaProperties
	}

}

上述示例使用由 @Qualifier("second") 限定的 DataSource bean 建立了一個 EntityManagerFactory。它掃描與 Order 位於同一包中的實體。可以使用 app.jpa 名稱空間對映其他 JPA 屬性。使用 @Bean(defaultCandidate=false) 允許定義 secondJpaPropertiessecondEntityManagerFactory bean,而不會干擾同類型的自動配置 bean。

Spring Framework 參考文件 更詳細地描述了此功能。

您應該為任何需要 JPA 訪問的更多額外資料來源提供類似的配置。為了完善功能,您還需要為每個 EntityManagerFactory 配置一個 JpaTransactionManager。或者,您可以使用一個涵蓋兩者的 JTA 事務管理器。

如果您使用 Spring Data,您需要相應地配置 @EnableJpaRepositories,如以下示例所示

  • Java

  • Kotlin

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "entityManagerFactory")
public class OrderConfiguration {

}
import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Order::class], entityManagerFactoryRef = "firstEntityManagerFactory")
class OrderConfiguration
  • Java

  • Kotlin

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory")
public class CustomerConfiguration {

}
import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Customer::class], entityManagerFactoryRef = "secondEntityManagerFactory")
class CustomerConfiguration

使用傳統的 persistence.xml 檔案

Spring Boot 預設不會搜尋或使用 META-INF/persistence.xml。如果您更喜歡使用傳統的 persistence.xml,則需要定義自己的 @Bean 型別為 LocalEntityManagerFactoryBean(ID 為“entityManagerFactory”),並在其中設定持久化單元名稱。

有關預設設定,請參閱 JpaBaseConfiguration

使用 Spring Data JPA 和 Mongo Repository

Spring Data JPA 和 Spring Data Mongo 都可以為您自動建立 Repository 實現。如果它們都在 classpath 中,您可能需要進行一些額外的配置來告訴 Spring Boot 要建立哪些儲存庫。最明確的方法是使用標準的 Spring Data @EnableJpaRepositories@EnableMongoRepositories 註解,並提供您的 Repository 介面的位置。

還有一些標誌(spring.data.*.repositories.enabledspring.data.*.repositories.type),您可以在外部配置中使用它們來開啟和關閉自動配置的儲存庫。這樣做很有用,例如,在您想要關閉 Mongo 儲存庫但仍使用自動配置的 MongoTemplate 的情況下。

對於其他自動配置的 Spring Data 儲存庫型別(Elasticsearch、Redis 等),存在相同的障礙和相同的功能。要使用它們,請相應地更改註解和標誌的名稱。

自定義 Spring Data 的 Web 支援

Spring Data 提供了 Web 支援,它簡化了在 Web 應用程式中使用 Spring Data 儲存庫。Spring Boot 在 spring.data.web 名稱空間中提供了屬性,用於自定義其配置。請注意,如果您正在使用 Spring Data REST,則必須使用 spring.data.rest 名稱空間中的屬性。

將 Spring Data 儲存庫作為 REST 端點公開

Spring Data REST 可以將 Repository 實現作為 REST 端點公開給您,前提是 Spring MVC 已為應用程式啟用。

Spring Boot 暴露了一組有用的屬性(來自 spring.data.rest 名稱空間),用於自定義 RepositoryRestConfiguration。如果您需要提供額外的自定義,您應該使用 RepositoryRestConfigurer bean。

如果您沒有為您的自定義 RepositoryRestConfigurer 指定任何順序,它將在 Spring Boot 內部使用的配置器之後執行。如果您需要指定順序,請確保它高於 0。

配置 JPA 使用的元件

如果您想配置 JPA 使用的元件,則需要確保該元件在 JPA 之前初始化。當元件自動配置時,Spring Boot 會為您處理這個問題。例如,當 Flyway 自動配置時,Hibernate 被配置為依賴 Flyway,這樣 Flyway 就有機會在 Hibernate 嘗試使用資料庫之前初始化資料庫。

如果您自己配置元件,您可以使用 EntityManagerFactoryDependsOnPostProcessor 子類作為設定必要依賴項的便捷方法。例如,如果您將 Hibernate Search 與 Elasticsearch 作為其索引管理器一起使用,則任何 EntityManagerFactory bean 都必須配置為依賴於 elasticsearchClient bean,如以下示例所示

  • Java

  • Kotlin

import jakarta.persistence.EntityManagerFactory;

import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.stereotype.Component;

/**
 * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
 * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
 */
@Component
public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
		extends EntityManagerFactoryDependsOnPostProcessor {

	public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
		super("elasticsearchClient");
	}

}
import org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor
import org.springframework.stereotype.Component

@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
	EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")

使用兩個資料來源配置 jOOQ

如果您需要將 jOOQ 與多個數據源一起使用,您應該為每個資料來源建立自己的 DSLContext。有關更多詳細資訊,請參閱 JooqAutoConfiguration

特別是,ExceptionTranslatorExecuteListenerSpringTransactionProvider 可以重用以提供與自動配置使用單個 DataSource 時類似的功能。
© . This site is unofficial and not affiliated with VMware.