|
如需获取最新稳定版本,请使用 Spring Boot 4.0.4! |
数据访问
Spring Boot 包含多个用于操作数据源的 starter。 本节将解答与此相关的各种问题。
配置自定义数据源
要配置您自己的 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()
}
}
以下示例展示了如何通过设置属性来定义数据源:
-
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://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
然而,由于该方法的返回类型为DataSource,存在一个限制。
这会隐藏连接池的实际类型,因此不会为您的自定义DataSource生成配置属性元数据,且您的IDE中也不会提供自动补全功能。
为了解决这个问题,使用构建器的type(Class)方法来指定要构建的DataSource的类型,并更新该方法的返回类型。
例如,以下展示了如何创建一个带有HikariDataSource的DataSourceBuilder:
-
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 属性,这意味着您必须按如下方式重写配置:
-
Properties
-
YAML
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
为解决此问题,请使用 DataSourceProperties,它将为您处理从 url 到 jdbc-url 的转换。
您可以使用任何 DataSourceProperties 对象的 initializeDataSourceBuilder() 方法,从其状态初始化 DataSourceBuilder。
您可以注入 Spring Boot 自动创建的 DataSourceProperties,但是,这会将您的配置分散到 spring.datasource.* 和 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 到 jdbc-url 的转换,因此您可以按如下方式进行配置:
-
Properties
-
YAML
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
请注意,由于自定义配置在代码中指定使用 Hikari,因此 app.datasource.type 将不起作用。
如支持的连接池中所述,DataSourceBuilder支持多种不同的连接池。
要使用Hikari以外的其他连接池,需将其添加到类路径中,使用type(Class)方法指定要使用的连接池类,并更新@Bean方法的返回类型以匹配。
这还将为您提供所选特定连接池的配置属性元数据。
Spring Boot 会将 Hikari 特定的设置暴露为 spring.datasource.hikari。
本示例使用更通用的 configuration 子命名空间,因为该示例不支持多数据源实现。 |
请参阅配置数据源和DataSourceAutoConfiguration类以了解更多详情。
配置两个数据源
要定义额外的 DataSource,可以使用与上一节类似的方法。
一个关键区别是,DataSource @Bean 必须使用 defaultCandidate=false 声明。
这可以防止自动配置的 DataSource 回退。
| The 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 注解注入点。
自动配置的数据源和附加数据源可以按如下方式进行配置:
-
Properties
-
YAML
spring.datasource.url=jdbc:mysql://localhost/first
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.configuration.maximum-pool-size=30
app.datasource.url=jdbc:mysql://localhost/second
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.max-total=30
spring:
datasource:
url: "jdbc:mysql://localhost/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
app:
datasource:
url: "jdbc:mysql://localhost/second"
username: "dbuser"
password: "dbpass"
max-total: 30
更高级、特定于实现的自动配置 DataSource 的配置可通过 spring.datasource.configuration.* 属性进行。
您也可以将相同的概念应用于额外的 DataSource,如以下示例所示:
-
Java
-
Kotlin
import com.zaxxer.hikari.HikariDataSource;
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;
@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("second") DataSourceProperties dataSourceProperties) {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
import com.zaxxer.hikari.HikariDataSource
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
@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(@Qualifier("second") dataSourceProperties: DataSourceProperties): HikariDataSource {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
}
前面的示例使用与 Spring Boot 在自动配置中相同的逻辑来配置额外的数据源。
请注意,app.datasource.configuration.* 属性提供了基于所选实现的高级设置。
与配置单个自定义DataSource一样,可以使用DataSource上的type(Class)方法来自定义一个或两个DataSourceBuilder bean的类型。
有关支持类型的详细信息,请参阅支持的连接池。
使用 Spring Data 仓库
Spring Data 可以创建各种风格的 Repository 接口的实现。
只要这些 Repository 实现包含在其中一个 自动配置包中,Spring Boot 就会为您处理所有这些事项,通常是使用 @SpringBootApplication 或 @EnableAutoConfiguration 注解的主应用程序类所在的包(或其子包)。
对于许多应用程序,您只需将正确的 Spring Data 依赖项添加到类路径中即可。
JPA 有一个 spring-boot-starter-data-jpa,Mongodb 有一个 spring-boot-starter-data-mongodb,还有其他各种受支持技术的Starters。
要开始使用,请创建一些存储库接口来处理您的 @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,它将在创建 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 实例。
有关详细信息,请参阅 Hibernate 用户指南。
在 Hibernate 组件中使用依赖注入
默认情况下,Spring Boot 注册了一个使用 BeanContainer 的实现,该实现使用 BeanFactory,以便转换器和实体监听器可以使用常规的依赖注入。
您可以通过注册一个 HibernatePropertiesCustomizer 来禁用或调整此行为,该操作会移除或更改 hibernate.resource.beans.container 属性。
使用自定义 EntityManagerFactory
要完全控制 EntityManagerFactory 的配置,您需要添加一个名为 ‘entityManagerFactory’ 的 @Bean。
当存在该类型的 Bean 时,Spring Boot 自动配置会禁用其实体管理器。
当您自行创建 LocalContainerEntityManagerFactoryBean 的 Bean 时,在自动配置的 LocalContainerEntityManagerFactoryBean 创建过程中应用的任何自定义设置都将丢失。
请确保使用自动配置的 EntityManagerFactoryBuilder 以保留 JPA 和提供商属性。
如果您依赖 spring.jpa.* 属性来配置命名策略或 DDL 模式等内容,这一点尤为重要。 |
使用多个 EntityManagerFactory
如果您需要针对多个数据源使用 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.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 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.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
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 secondEntityManagerFactory(
@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) 可以在不干扰相同类型的自动配置 Bean 的情况下定义 secondJpaProperties 和 secondEntityManagerFactory Bean。
| The Spring Framework参考文档更详细地描述了此功能。 |
您应该为任何需要 JPA 访问的额外数据源提供类似的配置。
为了完善整个配置,您还需要为每个 JpaTransactionManager 配置一个 EntityManagerFactory。
或者,您也可以使用一个跨两者的 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 = "entityManagerFactory")
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 仓库
Spring Data JPA 和 Spring Data Mongo 都可以自动为您创建 Repository 实现。
如果它们都存在于类路径上,您可能需要进行一些额外配置,以告知 Spring Boot 要创建哪些仓库。
最明确的方法是使用标准的 Spring Data @EnableJpaRepositories 和 @EnableMongoRepositories 注解,并提供您的 Repository 接口的位置。
还有一些标志(spring.data.*.repositories.enabled 和 spring.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 MVC,Spring Data REST 就可以为您将 Repository 实现公开为 REST 端点。
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")
使用两个数据源配置 jOOQ
如果您需要在多个数据源中使用 jOOQ,您应该为每个数据源创建自己的 DSLContext。
请参阅 JooqAutoConfiguration 以获取更多详细信息。
特别是,ExceptionTranslatorExecuteListener 和 SpringTransactionProvider 可以复用以提供与单个 DataSource 的自动配置类似的功能。 |