84. Data Access
Spring Boot 包含许多用于处理数据源的启动器。本部分回答与这样做有关的问题。
84.1 配置自定义数据源
要配置自己的DataSource
,请在配置中定义该类型的@Bean
。 Spring Boot 在需要的任何地方(包括数据库初始化)重用DataSource
。如果需要外部化某些设置,则可以将DataSource
绑定到环境(请参阅“ 第 24.8.1 节,“第三方配置””)。
以下示例显示了如何在 Bean 中定义数据源:
@Bean
@ConfigurationProperties(prefix="app.datasource")
public DataSource dataSource() {
return new FancyDataSource();
}
以下示例显示如何通过设置属性来定义数据源:
app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30
假设FancyDataSource
具有 URL,用户名和池大小的常规 JavaBean 属性,则在DataSource
可用于其他组件之前,这些设置会自动绑定。常规database initialization也会发生(因此spring.datasource.*
的相关子集仍可以与您的自定义配置一起使用)。
Spring Boot 还提供了一个名为DataSourceBuilder
的 Util 生成器类,该类可用于创建标准数据源之一(如果它在 Classpath 中)。构建器可以根据 Classpath 上可用的内容来检测要使用的一个。它还基于 JDBC URL 自动检测驱动程序。
下面的示例演示如何使用DataSourceBuilder
创建数据源:
@Bean
@ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
要使用DataSource
运行应用程序,您需要的只是连接信息。还可以提供特定于池的设置。有关更多详细信息,请检查将在运行时使用的实现。
以下示例显示如何通过设置属性来定义 JDBC 数据源:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
但是,有一个陷阱。由于未公开连接池的实际类型,因此自定义DataSource
的元数据中不会生成任何键,并且 IDE 中也无法完成操作(因为DataSource
接口未公开任何属性)。另外,如果您碰巧在 Classpath 上有 Hikari,则此基本设置也不起作用,因为 Hikari 没有url
属性(但确实具有jdbcUrl
属性)。在这种情况下,您必须按照以下方式重写配置:
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.maximum-pool-size=30
您可以通过强制连接池使用并返回专用的实现而不是DataSource
来解决此问题。您无法在运行时更改实现,但是选项列表将是明确的。
以下示例显示了如何使用DataSourceBuilder
创建HikariDataSource
:
@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
您甚至可以利用DataSourceProperties
为您做的事情进一步 Developing,也就是,如果没有提供 URL,则为默认的嵌入式数据库提供合理的用户名和密码。您可以从任何DataSourceProperties
对象的状态轻松地初始化DataSourceBuilder
,因此还可以注入 Spring Boot 自动创建的数据源。但是,这会将您的配置分为两个名称空间:spring.datasource
上的url
,username
,password
,type
和driver
,其余的放在您的自定义名称空间(app.datasource
)上。为避免这种情况,可以在自定义名称空间上重新定义自定义DataSourceProperties
,如以下示例所示:
@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();
}
这个设置使您与 Spring Boot 默认为您保持同步,除了选择了一个专用连接池(以代码形式),并且其设置在app.datasource.configuration
子命名空间中公开之外。由于DataSourceProperties
正在为您处理url
/jdbcUrl
转换,因此您可以按以下方式进行配置:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
Tip
Spring Boot 会将针对 Hikari 的设置公开给spring.datasource.hikari
。本示例使用更通用的configuration
子命名空间,因为该示例不支持多个数据源实现。
Note
由于您的自定义配置选择使用 Hikari,因此app.datasource.type
无效。实际上,将使用您可以在此处设置的任何值初始化构建器,然后通过对.type()
的调用来覆盖构建器。
有关更多详细信息,请参见“ Spring Boot 功能”部分和DataSourceAutoConfiguration类中的“ 第 30.1 节“配置数据源””。
84.2 配置两个数据源
如果需要配置多个数据源,则可以应用上一节中介绍的相同技巧。但是,您必须将DataSource
实例之一标记为@Primary
,因为将来各种自动配置都希望能够按类型获得一个。
如果您创建自己的DataSource
,则自动配置将退出。在下面的示例中,我们提供与自动配置在主要数据源上提供的功能完全相同的功能:
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource() {
return firstDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
Tip
firstDataSourceProperties
必须标记为@Primary
,以便数据库初始化程序功能使用您的副本(如果使用初始化程序)。
这两个数据源也都必须进行高级定制。例如,您可以按以下方式配置它们:
app.datasource.first.url=jdbc:mysql://localhost/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://localhost/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30
您也可以将相同的概念应用于辅助DataSource
,如以下示例所示:
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource() {
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() {
return secondDataSourceProperties().initializeDataSourceBuilder()
.type(BasicDataSource.class).build();
}
前面的示例在自定义名称空间上配置两个数据源,其逻辑与 Spring Boot 在自动配置中使用的逻辑相同。请注意,每个configuration
子命名空间都根据所选实现提供高级设置。
84.3 使用 Spring 数据存储库
Spring Data 可以创建各种风格的@Repository
接口的实现。只要@Repositories
包含在@EnableAutoConfiguration
类的同一包(或子包)中,Spring Boot 就会为您处理所有这些操作。
对于许多应用程序,您所需要做的就是将正确的 Spring Data 依赖项放在 Classpath 上(对于 JPA,有spring-boot-starter-data-jpa
;对于 Mongodb 是spring-boot-starter-data-mongodb
),并创建了一些存储库接口来处理@Entity
对象。示例在JPA sample和Mongodb sample中。
Spring Boot 会根据找到的@EnableAutoConfiguration
来猜测您的@Repository
定义的位置。要获得更多控制权,请使用@EnableJpaRepositories
Comments(来自 Spring Data JPA)。
有关 Spring Data 的更多信息,请参见Spring Data 项目页面。
84.4 将@Entity 定义与 Spring 配置分开
Spring Boot 会根据找到的@EnableAutoConfiguration
来猜测您的@Entity
定义的位置。要获得更多控制权,可以使用@EntityScan
注解,如以下示例所示:
@Configuration
@EnableAutoConfiguration
@EntityScan(basePackageClasses=City.class)
public class Application {
//...
}
84.5 配置 JPA 属性
Spring Data JPA 已经提供了一些独立于供应商的配置选项(例如用于 SQL 日志记录的那些),并且 Spring Boot 公开了这些选项,还为 Hibernate 提供了一些其他选项作为外部配置属性。其中一些会根据上下文自动检测到,因此您不必进行设置。
spring.jpa.hibernate.ddl-auto
是一种特殊情况,因为根据运行时条件,它具有不同的默认值。如果使用嵌入式数据库,并且没有模式 Management 器(例如 Liquibase 或 Flyway)正在处理DataSource
,则默认为create-drop
。在所有其他情况下,它默认为none
。
还会根据当前的DataSource
自动检测要使用的方言,但是如果您要明确表示并绕过启动检查,则可以自己设置spring.jpa.database
。
Note
指定database
将导致配置良好的 Hibernate 方言。多个数据库有多个Dialect
,这可能不满足您的需求。在这种情况下,您可以将spring.jpa.database
设置为default
以便让 Hibernate 弄清楚,也可以通过设置spring.jpa.database-platform
属性来设置方言。
以下示例显示了最常用的设置选项:
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true
此外,创建本地EntityManagerFactory
时,spring.jpa.properties.*
中的所有属性都作为普通 JPA 属性(前缀被去除)传递。
Tip
如果您需要对 Hibernate 属性应用高级自定义,请考虑在创建EntityManagerFactory
之前注册将被调用的HibernatePropertiesCustomizer
bean。这优先于自动配置应用的任何内容。
84.6 配置 Hibernate 命名策略
Hibernate 使用两种不同的命名策略将名称从对象模型 Map 到相应的数据库名称。可以分别通过设置spring.jpa.hibernate.naming.physical-strategy
和spring.jpa.hibernate.naming.implicit-strategy
属性来配置物理和隐式策略实现的标准类名。或者,如果ImplicitNamingStrategy
或PhysicalNamingStrategy
bean 在应用程序上下文中可用,则 Hibernate 将自动配置为使用它们。
默认情况下,Spring Boot 使用SpringPhysicalNamingStrategy
配置物理命名策略。此实现提供了与 Hibernate 4 相同的表结构:所有点都由下划线替换,骆驼套也由下划线替换。默认情况下,所有表名均以小写形式生成,但是如果您的模式需要它,则可以覆盖该标志。
例如,一个TelephoneNumber
实体被 Map 到telephone_number
表。
如果您更喜欢使用 Hibernate 5 的默认设置,请设置以下属性:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
或者,您可以配置以下 bean:
@Bean
public PhysicalNamingStrategy physicalNamingStrategy() {
return new PhysicalNamingStrategyStandardImpl();
}
有关更多详细信息,请参见HibernateJpaAutoConfiguration和JpaBaseConfiguration。
84.7 配置 Hibernate 二级缓存
可以为一系列缓存提供程序配置 Hibernate second-level cache。与其将 Hibernate 配置为再次查找缓存提供程序,不如提供尽可能在上下文中可用的缓存提供程序。
如果您使用的是 JCache,这非常简单。首先,确保org.hibernate:hibernate-jcache
在 Classpath 上可用。然后,添加一个HibernatePropertiesCustomizer
bean,如以下示例所示:
@Configuration
public class HibernateSecondLevelCacheExample {
@Bean
public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(
JCacheCacheManager cacheManager) {
return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER,
cacheManager.getCacheManager());
}
}
这个定制器将配置 Hibernate 使用与应用程序相同的CacheManager
。也可以使用单独的CacheManager
实例。有关详细信息,请参阅Hibernate 用户指南。
84.8 在 Hibernate 组件中使用依赖注入
默认情况下,Spring Boot 注册使用BeanFactory
的BeanContainer
实现,以便转换器和实体侦听器可以使用常规依赖项注入。
您可以通过注册删除或更改hibernate.resource.beans.container
属性的HibernatePropertiesCustomizer
来禁用或调整此行为。
84.9 使用自定义 EntityManagerFactory
要完全控制EntityManagerFactory
的配置,您需要添加一个名为'entityManagerFactory'的@Bean
。如果存在这种类型的 Bean,Spring Boot 自动配置将关闭其实体 Management 器。
84.10 使用两个 EntityManager
即使默认的EntityManagerFactory
可以正常工作,您也需要定义一个新的。否则,该类型的第二个 bean 的存在将关闭默认值。为了简化操作,您可以使用 Spring Boot 提供的便捷的EntityManagerBuilder
。另外,您也可以直接从 Spring ORM 中使用LocalContainerEntityManagerFactoryBean
,如以下示例所示:
// add two data sources configured as above
@Bean
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(customerDataSource())
.packages(Customer.class)
.persistenceUnit("customers")
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(orderDataSource())
.packages(Order.class)
.persistenceUnit("orders")
.build();
}
上面的配置几乎可以独立工作。要完成图片,您还需要为两个EntityManagers
配置TransactionManagers
。如果将其中一个标记为@Primary
,则可以在 Spring Boot 中将其默认为JpaTransactionManager
拾取。另一个必须显式地注入到新实例中。另外,您也许可以使用跨这两者的 JTA 事务 Management 器。
如果使用 Spring Data,则需要相应地配置@EnableJpaRepositories
,如以下示例所示:
@Configuration
@EnableJpaRepositories(basePackageClasses = Customer.class,
entityManagerFactoryRef = "customerEntityManagerFactory")
public class CustomerConfiguration {
...
}
@Configuration
@EnableJpaRepositories(basePackageClasses = Order.class,
entityManagerFactoryRef = "orderEntityManagerFactory")
public class OrderConfiguration {
...
}
84.11 使用传统的 persistence.xml 文件
默认情况下,Spring Boot 不会搜索或使用META-INF/persistence.xml
。如果您喜欢使用传统的persistence.xml
,则需要定义自己的LocalEntityManagerFactoryBean
类型的@Bean
(ID 为'entityManagerFactory'),并在其中设置持久性单元名称。
默认设置请参见JpaBaseConfiguration。
84.12 使用 Spring Data JPA 和 Mongo 存储库
Spring Data JPA 和 Spring Data Mongo 都可以为您自动创建Repository
实现。如果它们都存在于 Classpath 中,则可能必须做一些额外的配置以告诉 Spring Boot 要创建哪个存储库。最明确的方法是使用标准 Spring Data @EnableJpaRepositories
和@EnableMongoRepositories
注解并提供Repository
接口的位置。
还有一些标志(spring.data.*.repositories.enabled
和spring.data.*.repositories.type
),可用于在外部配置中打开和关闭自动配置的存储库。这样做很有用,例如,如果您想关闭 Mongo 存储库并仍然使用自动配置的MongoTemplate
。
其他自动配置的 Spring Data 存储库类型(Elasticsearch,Solr 等)存在相同的障碍和相同的功能。要使用它们,请相应地更改 Comments 和标志的名称。
84.13 自定义 Spring Data 的 Web 支持
Spring Data 提供了 Web 支持,可简化 Web 应用程序中 Spring Data 存储库的使用。 Spring Boot 在spring.data.web
名称空间中提供了用于自定义其配置的属性。请注意,如果您使用的是 Spring Data REST,则必须改为使用spring.data.rest
名称空间中的属性。
84.14 将 Spring 数据存储库公开为 REST 端点
如果已为应用程序启用 Spring MVC,Spring Data REST 可以为您将Repository
实现作为 REST 端点公开。
Spring Boot 公开了一组自定义RepositoryRestConfiguration的有用属性(来自spring.data.rest
命名空间)。如果需要提供其他定制,则应使用RepositoryRestConfigurer bean。
Note
如果您未在自定义RepositoryRestConfigurer
上指定任何 Sequences,它将在一个 Spring Boot 内部使用之后运行。如果您需要指定一个订单,请确保它大于 0.
84.15 配置 JPA 使用的组件
如果要配置 JPA 使用的组件,则需要确保在 JPA 之前初始化该组件。当组件被自动配置后,Spring Boot 会为您处理。例如,当自动配置 Flyway 时,会将 Hibernate 配置为依赖 Flyway,以便 Flyway 在 Hibernate 尝试使用它之前有机会初始化数据库。
如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor
子类作为构建必要依赖关系的便捷方法。例如,如果您将 Hibernate Search 和 Elasticsearch 用作其索引 Management 器,则必须将任何EntityManagerFactory
bean 配置为依赖elasticsearchClient
bean,如以下示例所示:
/**
* {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
* {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
*/
@Configuration
static class ElasticsearchJpaDependencyConfiguration
extends EntityManagerFactoryDependsOnPostProcessor {
ElasticsearchJpaDependencyConfiguration() {
super("elasticsearchClient");
}
}
84.16 使用两个数据源配置 jOOQ
如果需要将 jOOQ 与多个数据源一起使用,则应该为每个数据源创建自己的DSLContext
。有关更多详细信息,请参考JooqAutoConfiguration。
Tip
特别是,JooqExceptionTranslator
和SpringTransactionProvider
可以重复使用,以提供与自动配置使用单个DataSource
相似的功能。