資料存取
Spring Boot 包含許多用於資料來源的 Starter。本節回答與此相關的問題。
組態自訂 DataSource
若要組態您自己的 DataSource
,請在您的組態中定義該類型的 @Bean
。Spring Boot 會在任何需要 DataSource
的地方重複使用您的 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(prefix = "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(prefix = "app.datasource")
fun dataSource(): SomeDataSource {
return SomeDataSource()
}
}
以下範例示範如何透過設定屬性來定義資料來源
-
Properties
-
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
的實用工具建構器類別,可用於建立標準資料來源之一 (如果它在類別路徑上)。建構器可以根據類別路徑上可用的內容偵測要使用哪個資料來源。它也會根據 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 資料來源
-
Properties
-
YAML
app.datasource.url=jdbc:mysql://127.0.0.1/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
url: "jdbc:mysql://127.0.0.1/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
但是,這裡有一個陷阱。由於未公開連線池的實際類型,因此不會在自訂 DataSource
的元數據中產生任何鍵,並且您的 IDE 中沒有完成功能 (因為 DataSource
介面未公開任何屬性)。此外,如果您碰巧在類別路徑上有 Hikari,則此基本設定無法運作,因為 Hikari 沒有 url
屬性 (但確實有 jdbcUrl
屬性)。在這種情況下,您必須將您的組態重寫如下
-
Properties
-
YAML
app.datasource.jdbc-url=jdbc:mysql://127.0.0.1/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
jdbc-url: "jdbc:mysql://127.0.0.1/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
您可以透過強制連線池使用並傳回專用實作而非 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()
}
}
您甚至可以更進一步,利用 DataSourceProperties
為您提供的功能 — 也就是說,如果未提供 URL,則提供具有合理使用者名稱和密碼的預設嵌入式資料庫。您可以輕鬆地從任何 DataSourceProperties
物件的狀態初始化 DataSourceBuilder
,因此您也可以注入 Spring Boot 自動建立的 DataSource。但是,這會將您的組態分成兩個命名空間:spring.datasource
上的 url
、username
、password
、type
和 driver
,以及自訂命名空間 (app.datasource
) 上的其餘部分。為了避免這種情況,您可以重新定義自訂 DataSourceProperties
在您的自訂命名空間上,如下列範例所示
-
Java
-
Kotlin
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
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
正在為您處理 url
/jdbcUrl
轉換,因此您可以將其組態如下
-
Properties
-
YAML
app.datasource.url=jdbc:mysql://127.0.0.1/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
datasource:
url: "jdbc:mysql://127.0.0.1/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
Spring Boot 會將 Hikari 特有的設定公開到 spring.datasource.hikari 。此範例使用更通用的 configuration 子命名空間,因為該範例不支援多個資料來源實作。 |
由於您的自訂組態選擇使用 Hikari,因此 app.datasource.type 無效。實際上,建構器會使用您可能在那裡設定的任何值初始化,然後被對 .type() 的呼叫覆寫。 |
請參閱 “Spring Boot 功能” 章節中的 組態 DataSource 和 DataSourceAutoConfiguration
類別以取得更多詳細資訊。
組態兩個 DataSources
如果您需要組態多個資料來源,您可以應用先前章節中描述的相同技巧。但是,您必須將其中一個 DataSource
實例標記為 @Primary
,因為後續的各種自動組態期望能夠依類型取得一個。
如果您建立自己的 DataSource
,則自動組態會退回。在以下範例中,我們提供與自動組態在主要資料來源上提供的完全相同的功能集
-
Java
-
Kotlin
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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;
import org.springframework.context.annotation.Primary;
@Configuration(proxyBeanMethods = false)
public class MyDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
import com.zaxxer.hikari.HikariDataSource
import org.apache.commons.dbcp2.BasicDataSource
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
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
import org.springframework.context.annotation.Primary
@Configuration(proxyBeanMethods = false)
class MyDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSource(): BasicDataSource {
return DataSourceBuilder.create().type(BasicDataSource::class.java).build()
}
}
firstDataSourceProperties 必須標記為 @Primary ,以便資料庫初始化程式功能使用您的副本 (如果您使用初始化程式)。 |
這兩個資料來源也綁定用於進階自訂。例如,您可以將它們組態如下
-
Properties
-
YAML
app.datasource.first.url=jdbc:mysql://127.0.0.1/first
app.datasource.first.username=dbuser
app.datasource.first.password=dbpass
app.datasource.first.configuration.maximum-pool-size=30
app.datasource.second.url=jdbc:mysql://127.0.0.1/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30
app:
datasource:
first:
url: "jdbc:mysql://127.0.0.1/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
second:
url: "jdbc:mysql://127.0.0.1/second"
username: "dbuser"
password: "dbpass"
max-total: 30
您可以將相同的概念應用於次要 DataSource
,如下列範例所示
-
Java
-
Kotlin
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration(proxyBeanMethods = false)
public class MyCompleteDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
public BasicDataSource secondDataSource(
@Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
}
import com.zaxxer.hikari.HikariDataSource
import org.apache.commons.dbcp2.BasicDataSource
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
@Configuration(proxyBeanMethods = false)
class MyCompleteDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
fun secondDataSource(secondDataSourceProperties: DataSourceProperties): BasicDataSource {
return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource::class.java).build()
}
}
先前的範例在自訂命名空間上組態了兩個資料來源,其邏輯與 Spring Boot 在自動組態中使用的邏輯相同。請注意,每個 configuration
子命名空間都根據所選的實作提供進階設定。
使用 Spring Data Repositories
Spring Data 可以建立各種風格的 Repository
介面的實作。Spring Boot 為您處理所有這些,只要這些 Repository
實作包含在 自動組態套件 之一中,通常是使用 @SpringBootApplication
或 @EnableAutoConfiguration
註解的主要應用程式類別的套件 (或子套件)。
對於許多應用程式,您只需要將正確的 Spring Data 依賴放在您的類別路徑上。JPA 有 spring-boot-starter-data-jpa
,Mongodb 有 spring-boot-starter-data-mongodb
,以及其他各種 Starter 用於支援的技術。若要開始使用,請建立一些 Repository 介面來處理您的 @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.autoconfigure.domain.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.autoconfigure.domain.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
屬性。
以下範例顯示了要設定的最常見選項
-
Properties
-
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 屬性傳遞 (並剝離前綴)。
您需要確保在 例如,如果您要組態 Hibernate 的批次大小,則必須使用 |
如果您需要對 Hibernate 屬性套用進階自訂,請考慮註冊一個 HibernatePropertiesCustomizer Bean,該 Bean 將在建立 EntityManagerFactory 之前被調用。這優先於自動組態套用的任何內容。 |
組態 Hibernate 命名策略
Hibernate 使用 兩種不同的命名策略 來將名稱從物件模型對應到對應的資料庫名稱。可以透過設定 spring.jpa.hibernate.naming.physical-strategy
和 spring.jpa.hibernate.naming.implicit-strategy
屬性,組態物理策略和隱含策略實作的完整類別名稱。或者,如果 ImplicitNamingStrategy
或 PhysicalNamingStrategy
Bean 在應用程式上下文中可用,則會自動組態 Hibernate 以使用它們。
依預設,Spring Boot 使用 CamelCaseToUnderscoresNamingStrategy
組態物理命名策略。使用此策略,所有點都會替換為底線,並且駝峰式大小寫也會替換為底線。此外,依預設,所有表格名稱都以小寫產生。例如,TelephoneNumber
實體會對應到 telephone_number
表格。如果您的架構需要混合大小寫識別碼,請定義自訂 CamelCaseToUnderscoresNamingStrategy
Bean,如下列範例所示
-
Java
-
Kotlin
import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy;
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 CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
return new CamelCaseToUnderscoresNamingStrategy() {
@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
};
}
}
import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
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(): CamelCaseToUnderscoresNamingStrategy {
return object : CamelCaseToUnderscoresNamingStrategy() {
override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean {
return false
}
}
}
}
如果您偏好使用 Hibernate 的預設值,請設定以下屬性
-
Properties
-
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()
}
}
請參閱 HibernateJpaAutoConfiguration
和 JpaBaseConfiguration
以取得更多詳細資訊。
組態 Hibernate 第二層快取
Hibernate 第二層快取 可以針對各種快取提供者進行組態。最好提供上下文中可用的快取提供者,而不是組態 Hibernate 再次查閱快取提供者。
若要使用 JCache 執行此操作,請先確保類別路徑上提供 org.hibernate.orm:hibernate-jcache
。然後,新增一個 HibernatePropertiesCustomizer
Bean,如下列範例所示
-
Java
-
Kotlin
import org.hibernate.cache.jcache.ConfigSettings;
import org.springframework.boot.autoconfigure.orm.jpa.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.autoconfigure.orm.jpa.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 ->
properties[ConfigSettings.CACHE_MANAGER] = cacheManager.cacheManager
}
}
}
此自訂器將組態 Hibernate 以使用與應用程式使用的 CacheManager
相同的 CacheManager
。也可以使用個別的 CacheManager
實例。有關詳細資訊,請參閱 Hibernate 使用者指南。
在 Hibernate 元件中使用依賴注入
依預設,Spring Boot 會註冊一個使用 BeanFactory
的 BeanContainer
實作,以便轉換器和實體監聽器可以使用常規依賴注入。
您可以透過註冊一個 HibernatePropertiesCustomizer
來停用或調整此行為,該自訂器會移除或變更 hibernate.resource.beans.container
屬性。
使用自訂 EntityManagerFactory
若要完全控制 EntityManagerFactory
的組態,您需要新增一個名為 ‘entityManagerFactory’ 的 @Bean
。在存在該類型的 Bean 時,Spring Boot 自動組態會關閉其實體管理器。
使用多個 EntityManagerFactories
如果您需要針對多個資料來源使用 JPA,您可能需要每個資料來源一個 EntityManagerFactory
。來自 Spring ORM 的 LocalContainerEntityManagerFactoryBean
可讓您針對您的需求組態 EntityManagerFactory
。您也可以重複使用 JpaProperties
來綁定每個 EntityManagerFactory
的設定,如下列範例所示
-
Java
-
Kotlin
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
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 MyEntityManagerFactoryConfiguration {
@Bean
@ConfigurationProperties("app.jpa.first")
public JpaProperties firstJpaProperties() {
return new JpaProperties();
}
@Bean
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
JpaProperties firstJpaProperties) {
EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
}
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
}
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
// ... map JPA properties as needed
return new HibernateJpaVendorAdapter();
}
}
import javax.sql.DataSource
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
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)
class MyEntityManagerFactoryConfiguration {
@Bean
@ConfigurationProperties("app.jpa.first")
fun firstJpaProperties(): JpaProperties {
return JpaProperties()
}
@Bean
fun firstEntityManagerFactory(
firstDataSource: DataSource?,
firstJpaProperties: JpaProperties
): LocalContainerEntityManagerFactoryBean {
val builder = createEntityManagerFactoryBuilder(firstJpaProperties)
return builder.dataSource(firstDataSource).packages(Order::class.java).persistenceUnit("firstDs").build()
}
private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.properties, null)
}
private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
// ... map JPA properties as needed
return HibernateJpaVendorAdapter()
}
}
上面的範例使用名為 firstDataSource
的 DataSource
Bean 建立 EntityManagerFactory
。它會掃描與 Order
位於同一套件中的實體。可以使用 app.first.jpa
命名空間對應其他 JPA 屬性。
當您自己為 LocalContainerEntityManagerFactoryBean 建立 Bean 時,在自動組態的 LocalContainerEntityManagerFactoryBean 建立期間套用的任何自訂都會遺失。例如,對於 Hibernate,spring.jpa.hibernate 前綴下的任何屬性都不會自動套用至您的 LocalContainerEntityManagerFactoryBean 。如果您依賴這些屬性來組態命名策略或 DDL 模式之類的事項,則在建立 LocalContainerEntityManagerFactoryBean Bean 時,您需要明確組態。 |
對於您需要 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 = "firstEntityManagerFactory")
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
,則需要定義您自己的 LocalEntityManagerFactoryBean
類型的 @Bean
(ID 為 ‘entityManagerFactory’),並在那裡設定持久性單元名稱。
請參閱 JpaBaseConfiguration
以取得預設設定。
使用 Spring Data JPA 和 Mongo Repositories
Spring Data JPA 和 Spring Data Mongo 都可以自動為您建立 Repository
實作。如果它們都存在於類別路徑上,您可能必須執行一些額外的組態,以告知 Spring Boot 要建立哪些 Repository。最明確的方法是使用標準 Spring Data @EnableJpaRepositories
和 @EnableMongoRepositories
註解,並提供您的 Repository
介面的位置。
還有一些旗標 (spring.data.*.repositories.enabled
和 spring.data.*.repositories.type
) 可用於在外部組態中開啟和關閉自動組態的 Repository。例如,如果您想要關閉 Mongo Repository 並仍然使用自動組態的 MongoTemplate
,則這樣做很有用。
其他自動組態的 Spring Data Repository 類型 (Elasticsearch、Redis 和其他類型) 也存在相同的障礙和相同的功能。若要使用它們,請相應地變更註解和旗標的名稱。
自訂 Spring Data 的 Web 支援
Spring Data 提供 Web 支援,可簡化在 Web 應用程式中使用 Spring Data Repository。Spring Boot 在 spring.data.web
命名空間中提供屬性,用於自訂其組態。請注意,如果您使用的是 Spring Data REST,則必須改用 spring.data.rest
命名空間中的屬性。
將 Spring Data Repositories 公開為 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.autoconfigure.orm.jpa.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.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor
import org.springframework.stereotype.Component
@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")
使用兩個 DataSources 組態 jOOQ
如果您需要將 jOOQ 與多個資料來源搭配使用,則應為每個資料來源建立自己的 DSLContext
。請參閱 JooqAutoConfiguration
以取得更多詳細資訊。
特別是,JooqExceptionTranslator 和 SpringTransactionProvider 可以重複使用,以提供與自動組態使用單一 DataSource 提供的功能類似的功能。 |