数据访问

Spring Boot 包含多个用于处理数据源的 Starter。 本节将解答与此相关的常见问题。spring-doc.cadn.net.cn

配置自定义数据源

要配置您自己的 DataSource,请在您的配置中定义一个该类型的 @Bean。 Spring Boot 会在任何需要该对象的地方重用您的 DataSource,包括数据库初始化。 如果您需要外部化某些设置,可以将您的 DataSource 绑定到环境(请参阅 第三方配置)。spring-doc.cadn.net.cn

以下示例展示了如何在 Bean 中定义数据源:spring-doc.cadn.net.cn

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()
	}

}

以下示例展示了如何通过设置数据源的属性来定义数据源:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

Spring Boot 还提供了一个实用的构建器类,名为 DataSourceBuilder,可用于创建标准数据源之一(如果该类位于类路径上)。 该构建器可以根据类路径上的可用内容检测应使用哪一个数据源。 它还会根据 JDBC URL 自动检测驱动程序。spring-doc.cadn.net.cn

以下示例展示了如何使用 DataSourceBuilder 创建数据源:spring-doc.cadn.net.cn

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 运行应用程序,您只需要连接信息。 也可以提供特定于连接池的设置。 请查看运行时将使用的实现以获取更多详细信息。spring-doc.cadn.net.cn

以下示例展示了如何通过设置属性来定义 JDBC 数据源:spring-doc.cadn.net.cn

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 类型,并更新方法的返回类型。 例如,以下展示了如何使用 DataSourceBuilder 创建 HikariDataSourcespring-doc.cadn.net.cn

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 属性,这意味着你必须将配置重写如下:spring-doc.cadn.net.cn

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,它将为您处理从 urljdbc-url 的转换。 您可以使用任何 DataSourceProperties 对象的 initializeDataSourceBuilder() 方法,从其状态初始化一个 DataSourceBuilder。 您可以注入 Spring Boot 自动创建的 DataSourceProperties,但这会将您的配置分散在 spring.datasource.*app.datasource.* 中。 为避免这种情况,请定义一个带有自定义配置属性前缀的自定义 DataSourceProperties,如下例所示:spring-doc.cadn.net.cn

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 的转换,因此您可以按如下方式进行配置:spring-doc.cadn.net.cn

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 将不会生效。spring-doc.cadn.net.cn

正如支持的连接池中所述,DataSourceBuilder支持多种不同的连接池。 若要使用 Hikari 以外的连接池,请将其添加到类路径中,使用type(Class)方法指定要使用的连接池类,并更新@Bean方法的返回类型以匹配。 这还将为您提供所选特定连接池的配置属性元数据。spring-doc.cadn.net.cn

Spring Boot 会将 Hikari 特有的配置项暴露在 spring.datasource.hikari 下。 本示例使用了更为通用的 configuration 子命名空间,因为该示例不支持多种数据源实现。

请参阅 配置数据源DataSourceAutoConfiguration 类以获取更多详情。spring-doc.cadn.net.cn

配置两个数据源

要定义额外的 DataSource,可以使用与上一节类似的方法。 一个关键区别是,DataSource @Bean 必须使用 defaultCandidate=false 进行声明。 这可以防止自动配置的 DataSource 回退。spring-doc.cadn.net.cn

Spring Framework 参考文档 对此功能进行了更详细的描述。

为了允许在需要的地方注入额外的 DataSource,请同时使用 @Qualifier 对其进行注解,如下例所示:spring-doc.cadn.net.cn

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 标注注入点。spring-doc.cadn.net.cn

自动配置的数据源和额外的数据源可以按如下方式配置:spring-doc.cadn.net.cn

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,如下例所示:spring-doc.cadn.net.cn

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("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.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(@Qualifier("second") dataSourceProperties: DataSourceProperties): HikariDataSource {
		return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
	}

}

前面的示例使用与 Spring Boot 在自动配置中所采用的相同逻辑来配置额外的数据源。 请注意,app.datasource.configuration.* 属性根据所选的实现提供了高级设置。spring-doc.cadn.net.cn

配置单个自定义DataSource一样,可以使用 DataSourceBuilder 上的 type(Class) 方法来自定义一个或两个 DataSource Bean 的类型。 有关支持类型的详细信息,请参阅 支持的连接池spring-doc.cadn.net.cn

使用 Spring Data 仓库

Spring Data 可以创建各种风格的 Repository 接口的实现。 只要这些 Repository 实现包含在某个 自动配置包 中(通常是用 @SpringBootApplication@EnableAutoConfiguration 注解的主应用程序类所在的包或其子包),Spring Boot 就会为您处理所有这些内容。spring-doc.cadn.net.cn

对于许多应用程序,您只需将正确的 Spring Data 依赖项添加到类路径中。 JPA 有一个 spring-boot-starter-data-jpa,Mongodb 有一个 spring-boot-starter-data-mongodb,还有其他各种受支持技术的Starters。 要开始使用,请创建一些仓库接口来处理您的 @Entity 对象。spring-doc.cadn.net.cn

Spring Boot 通过扫描自动配置包来确定您的 Repository 实现的位置。 如需更多控制,请使用 Spring Data 提供的 @Enable…Repositories 注解。spring-doc.cadn.net.cn

有关 Spring Data 的更多信息,请参见 Spring Data 项目页面spring-doc.cadn.net.cn

将 @Entity 定义与 Spring 配置分离

Spring Boot 通过扫描自动配置包来确定您的 @Entity 定义的位置。 如需更多控制,请使用 @EntityScan 注解,如下例所示:spring-doc.cadn.net.cn

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 定义

可以使用 @Entity bean 来过滤 ManagedClassNameFilter 定义。 这在测试中非常有用,当只需要考虑可用实体的一个子集时。 在以下示例中,仅包含来自 com.example.app.customer 包的实体:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

spring.jpa.hibernate.ddl-auto 是一个特殊情况,因为根据运行时条件,它具有不同的默认值。 如果使用了嵌入式数据库,并且没有架构管理工具(如 Liquibase 或 Flyway)来管理 DataSource,则默认值为 create-drop。 在所有其他情况下,默认值为 nonespring-doc.cadn.net.cn

所使用的方言由 JPA 提供商自动检测。 如果您希望自行设置方言,请配置 spring.jpa.database-platform 属性。spring-doc.cadn.net.cn

以下示例展示了最常用的配置选项:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

您需要确保在 spring.jpa.properties.* 下定义的名称与您的 JPA 提供商所期望的名称完全匹配。 Spring Boot 不会对这些条目执行任何形式的宽松绑定。spring-doc.cadn.net.cn

例如,如果你想配置 Hibernate 的批处理大小,必须使用 spring.jpa.properties.hibernate.jdbc.batch_size。 如果你使用其他形式,例如 batchSizebatch-size,Hibernate 将不会应用该设置。spring-doc.cadn.net.cn

如果您需要对 Hibernate 属性进行高级自定义,可以考虑注册一个 HibernatePropertiesCustomizer Bean,该 Bean 将在创建 EntityManagerFactory 之前被调用。 此操作的优先级高于自动配置所应用的任何设置。

配置 Hibernate 命名策略

Hibernate 使用 两种不同的命名策略 将对象模型中的名称映射到相应的数据库名称。 可以通过设置 spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy 属性,分别配置物理策略实现和隐式策略实现的完全限定类名。 或者,如果应用程序上下文中存在 ImplicitNamingStrategyPhysicalNamingStrategy Bean,Hibernate 将自动配置为使用它们。spring-doc.cadn.net.cn

默认情况下,Spring Boot 使用 CamelCaseToUnderscoresNamingStrategy 配置物理命名策略。 使用该策略时,所有的点号会被替换为下划线,驼峰命名也会被替换为下划线。 此外,默认情况下,所有表名均以小写生成。 例如,TelephoneNumber 实体将映射到 telephone_number 表。 如果您的模式需要混合大小写的标识符,请定义一个自定义的 CamelCaseToUnderscoresNamingStrategy Bean,如下例所示:spring-doc.cadn.net.cn

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 的默认设置,请设置以下属性:spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

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()
	}

}

配置 Hibernate 二级缓存

Hibernate 二级缓存可以配置为多种缓存提供者。 与其让 Hibernate 再次查找缓存提供者,不如尽可能提供上下文中已有的缓存提供者。spring-doc.cadn.net.cn

要使用 JCache 实现此功能,首先请确保 org.hibernate.orm:hibernate-jcache 在类路径中可用。 然后,添加一个 HibernatePropertiesCustomizer Bean,如下例所示:spring-doc.cadn.net.cn

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 用户指南spring-doc.cadn.net.cn

在 Hibernate 组件中使用依赖注入

默认情况下,Spring Boot 会注册一个使用 BeanFactoryBeanContainer 实现,以便转换器和实体监听器可以使用常规的依赖注入。spring-doc.cadn.net.cn

您可以通过注册一个 HibernatePropertiesCustomizer 来禁用或调整此行为,该注册器会移除或更改 hibernate.resource.beans.container 属性。spring-doc.cadn.net.cn

使用自定义 EntityManagerFactory

要完全控制 EntityManagerFactory 的配置,您需要添加一个名为 'entityManagerFactory' 的 @Bean。 当存在该类型的 Bean 时,Spring Boot 自动配置将禁用其实体管理器。spring-doc.cadn.net.cn

当您自己为 LocalContainerEntityManagerFactoryBean 创建 Bean 时,在自动配置的 LocalContainerEntityManagerFactoryBean 创建过程中应用的任何自定义设置都将丢失。 请确保使用自动配置的 EntityManagerFactoryBuilder 以保留 JPA 和厂商特定属性。 如果您依赖 spring.jpa.* 属性来配置命名策略或 DDL 模式等内容,这一点尤为重要。

使用多个 EntityManagerFactory

如果您需要针对多个数据源使用 JPA,则每个数据源可能需要一个 EntityManagerFactory。 来自 Spring ORM 的 LocalContainerEntityManagerFactoryBean 允许您根据需求配置 EntityManagerFactory。 您还可以复用 JpaProperties 来绑定第二个 EntityManagerFactory 的设置。 基于 配置第二个 DataSource 的示例,可以按以下示例定义第二个 EntityManagerFactoryspring-doc.cadn.net.cn

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 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) 可以定义 secondJpaPropertiessecondEntityManagerFactory Bean,而不会干扰同类型的自动配置 Bean。spring-doc.cadn.net.cn

Spring Framework 参考文档 对此功能进行了更详细的描述。

您应该为任何需要 JPA 访问的其他数据源提供类似的配置。 为了完善整体架构,您还需要为每个 JpaTransactionManager 配置一个 EntityManagerFactory。 或者,您也可以使用一个涵盖两者的 JTA 事务管理器。spring-doc.cadn.net.cn

如果您使用 Spring Data,则需要相应地配置 @EnableJpaRepositories,如下例所示:spring-doc.cadn.net.cn

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
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,则需要定义您自己的类型为 @BeanLocalEntityManagerFactoryBean(ID 为 'entityManagerFactory'),并在那里设置持久化单元名称。spring-doc.cadn.net.cn

请参阅 JpaBaseConfiguration 了解默认设置。spring-doc.cadn.net.cn

使用 Spring Data JPA 和 Mongo 仓库

Spring Data JPA 和 Spring Data Mongo 都可以自动为您创建 Repository 实现。 如果两者都存在于类路径上,您可能需要进行一些额外配置,以告知 Spring Boot 要创建哪些仓库。 最明确的方法是使用标准的 Spring Data @EnableJpaRepositories@EnableMongoRepositories 注解,并提供您的 Repository 接口的位置。spring-doc.cadn.net.cn

还有一些标志(spring.data.*.repositories.enabledspring.data.*.repositories.type),您可以在外部配置中使用它们来开启或关闭自动配置的仓库。 例如,在您希望禁用 Mongo 仓库但仍使用自动配置的 MongoTemplate 时,这样做非常有用。spring-doc.cadn.net.cn

其他自动配置的 Spring Data 仓库类型(如 Elasticsearch、Redis 等)也存在相同的障碍和相同的功能特性。 要使用它们,请相应地更改注解和标志的名称。spring-doc.cadn.net.cn

自定义 Spring Data 的 Web 支持

Spring Data 提供了 Web 支持,可简化在 Web 应用程序中使用 Spring Data 仓库。 Spring Boot 在 spring.data.web 命名空间中提供了用于自定义其配置的属性。 请注意,如果您使用的是 Spring Data REST,则必须改用 spring.data.rest 命名空间中的属性。spring-doc.cadn.net.cn

将 Spring Data 仓库暴露为 REST 端点

Spring Data REST 可以为您将 Repository 实现暴露为 REST 端点, 前提是应用程序已启用 Spring MVC。spring-doc.cadn.net.cn

Spring Boot 提供了一组有用的属性(来自 spring.data.rest 命名空间),用于自定义 RepositoryRestConfiguration。 如果您需要提供额外的自定义,您应该使用一个 RepositoryRestConfigurer Bean。spring-doc.cadn.net.cn

如果您未对自定义的 RepositoryRestConfigurer 指定任何顺序,它将在 Spring Boot 内部使用的顺序之后运行。 如果需要指定顺序,请确保其值大于 0。

配置由 JPA 使用的组件

如果你想配置 JPA 所使用的某个组件,那么你需要确保该组件在 JPA 之前完成初始化。 当该组件是自动配置时,Spring Boot 会为你处理好这一点。 例如,当 Flyway 被自动配置时,Hibernate 会被设置为依赖 Flyway,这样 Flyway 就有机会在 Hibernate 尝试使用数据库之前完成数据库的初始化。spring-doc.cadn.net.cn

如果您自行配置组件,可以使用 EntityManagerFactoryDependsOnPostProcessor 子类作为设置必要依赖关系的便捷方式。 例如,如果您使用 Hibernate Search 并将 Elasticsearch 作为其索引管理器,则任何 EntityManagerFactory Bean 都必须配置为依赖于 elasticsearchClient Bean,如下例所示:spring-doc.cadn.net.cn

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 以获取更多详细信息。spring-doc.cadn.net.cn

特别是,ExceptionTranslatorExecuteListenerSpringTransactionProvider 可以复用,以提供与单个 DataSource 的自动配置类似的功能。