20191128 Spring Boot官方文档学习(9.9)
9.9。数据存取
Spring Boot包含许多用于处理数据源的启动器。
9.9.1。配置自定义数据源
要配置自己的DataSource
,请在配置中定义该类型的@Bean。Spring Boot可以在任何需要重用DataSource的地方重复使用,包括数据库初始化。如果需要外部化某些设置,则可以将其绑定DataSource到Environment。
以下示例显示了如何在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用于其他组件之前,将自动绑定这些设置。常规的数据库初始化也会发生(因此spring.datasource.*
的相关子集仍可以与您的自定义配置一起使用)。
Spring Boot还提供了一个名为DataSourceBuilder
的实用程序生成器类,可用于创建标准数据源之一(如果它位于类路径上)。构建器可以根据类路径中可用的内容来检测要使用的一个。它还基于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接口未公开任何属性)。另外,如果您碰巧在类路径上有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
为您提供服务的功能(即,如果没有提供URL,则通过提供一个默认的嵌入式数据库以及一个明智的用户名和密码)来进一步发展。您可以轻松地从任何DataSourceProperties对象的状态初始化DataSourceBuilder
,因此您还可以注入Spring Boot自动创建的DataSource。然而,这将配置分为两个命名空间: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
Spring Boot会将Hikari特定的设置公开给spring.datasource.hikari
。本示例使用更通用的configuration子名称空间,因为该示例不支持多个数据源实现。
由于您的自定义配置选择与Hikari一起使用,因此app.datasource.type无效。实际上,构建器会使用.type()的任何值。
有关更多详细信息,请参见“Spring Boot功能”部分中的“ 配置数据源”和DataSourceAutoConfiguration
类。
9.9.2。配置两个数据源
如果需要配置多个数据源,则可以应用上一节中介绍的相同技巧。但是,您必须将其中一个DataSource实例标记为@Primary
,因为将来各种自动配置都希望能够按类型获得一个DataSource。
如果您创建自己的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();
}
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子名称空间都基于所选实现提供高级设置。
9.9.3。使用Spring Data Repositories
Spring Data可以创建各种类型的@Repository接口的实现。只要@Repositories
包含在@EnableAutoConfiguration
类的同一包(或子包)中,Spring Boot就会为您处理所有这些操作。
对于许多应用程序,您所需要做的就是在类路径上放置正确的Spring Data依赖项。JPA 有一个spring-boot-starter-data-jpa
,Mongodb 有一个spring-boot-starter-data-mongodb
等。要开始使用,请创建一些仓库接口来处理您的@Entity对象。
Spring Boot会根据@EnableAutoConfiguration
发现的内容尝试猜测您的@Repository
定义的位置。要获得更多控制权,请使用@EnableJpaRepositories
注释(来自Spring Data JPA)。
有关Spring Data的更多信息,请参见Spring Data项目页面。
9.9.4。将@Entity定义与Spring配置分开
Spring Boot会根据@EnableAutoConfiguration
发现的内容尝试猜测您定义的@Entity
的位置。要获得更多控制,可以使用@EntityScan
注释,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses=City.class)
public class Application {
//...
}
9.9.5。配置JPA属性
Spring Data JPA已经提供了一些独立于供应商的配置选项(例如用于SQL日志记录的那些),并且Spring Boot公开了这些选项,还为Hibernate提供了更多选项作为外部配置属性。其中的一些会根据上下文自动检测到,因此您不必进行设置。
spring.jpa.hibernate.ddl-auto
是一种特殊情况,因为根据运行时条件,它具有不同的默认值。如果使用嵌入式数据库并且没有模式管理器(例如Liquibase或Flyway)正在处理DataSource,则默认为create-drop
。在所有其他情况下,默认为none
。
JPA提供方检测要使用的方言。如果您希望自己设置方言,请设置spring.jpa.database-platform
属性。
下例显示了最常用的设置选项:
spring.jpa.hibernate.naming.physical-strategy = com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql = true
此外,创建本地EntityManagerFactory
时,所有spring.jpa.properties.*
属性均作为常规JPA属性(前缀被去除)传递。
您需要确保在下面定义的名称spring.jpa.properties.*
与您的JPA提供程序期望的名称完全匹配。Spring Boot不会尝试对这些条目进行任何形式的宽松绑定。
例如,如果要配置Hibernate的批处理大小,则必须使用spring.jpa.properties.hibernate.jdbc.batch_size
。如果您使用其他形式,例如batchSize或batch-size,则Hibernate将不会应用该设置。
如果您需要对Hibernate属性应用高级自定义,请考虑在创建EntityManagerFactory
之前注册将被调用的HibernatePropertiesCustomizer
bean 。这优先于自动配置应用的任何内容。
9.9.6。配置Hibernate命名策略
Hibernate使用两种不同的命名策略将名称从对象模型映射到相应的数据库名称。可以分别通过设置spring.jpa.hibernate.naming.physical-strategy
和spring.jpa.hibernate.naming.implicit-strategy
属性来配置物理和隐式策略实现的标准类名。替代地,如果ImplicitNamingStrategy
或PhysicalNamingStrategy
bean在应用程序上下文是可用的,Hibernate会被自动配置为使用它们。
默认情况下,Spring Boot用SpringPhysicalNamingStrategy
配置物理命名策略。此实现提供了与Hibernate 4相同的表结构:所有点都由下划线替换,而驼峰语法也由下划线替换。默认情况下,所有表名均以小写形式生成,但是如果您的架构需要它,则可以覆盖该标志。
例如,一个TelephoneNumber实体被映射到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
了解更多详细信息。
9.9.7。配置Hibernate二级缓存
可以为一系列缓存提供方配置Hibernate 二级缓存。与其将Hibernate配置为再次查找缓存提供程序,不如提供尽可能在上下文中可用的缓存提供方。
如果您使用的是JCache,这非常简单。首先,确保org.hibernate:hibernate-jcache
在类路径上可用。然后,添加一个HibernatePropertiesCustomizer
bean,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class HibernateSecondLevelCacheExample {
@Bean
public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
}
}
该定制器将配置Hibernate以使其与应用程序使用的CacheManager
相同。也可以使用单独的CacheManager实例。有关详细信息,请参阅《Hibernate用户指南》。
9.9.8。在Hibernate组件中使用依赖注入
默认情况下,Spring Boot注册使用BeanFactory
的BeanContainer
实现,以便转换器和实体侦听器可以使用常规依赖项注入。
您可以通过注册HibernatePropertiesCustomizer
删除或更改hibernate.resource.beans.container
属性的来禁用或调整此行为。
9.9.9。使用自定义EntityManagerFactory
要完全控制EntityManagerFactory
的配置,您需要添加一个名为entityManagerFactory
的@Bean。如果存在这种类型的Bean,Spring Boot自动配置将关闭其实体管理器。
9.9.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
可以将其选中。另一个必须显式地注入到新实例中。另外,您也许可以使用跨两个EntityManagers
的JTA事务管理器。
如果使用Spring Data,则需要进行相应的@EnableJpaRepositories
配置,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class,
entityManagerFactoryRef = "customerEntityManagerFactory")
public class CustomerConfiguration {
...
}
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class,
entityManagerFactoryRef = "orderEntityManagerFactory")
public class OrderConfiguration {
...
}
9.9.11。使用传统persistence.xml文件
默认情况下,Spring Boot不会搜索或使用META-INF/persistence.xml
。如果您喜欢使用传统的persistence.xml,则需要定义自己的LocalEntityManagerFactoryBean
类型的@Bean(ID为entityManagerFactory
)并在其中设置持久性单元名称。
请参阅JpaBaseConfiguration
以获取默认设置。
9.9.12。使用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,Solr等),存在相同的障碍和相同的功能。要使用它们,请相应地更改注释和标志的名称。
9.9.13。定制Spring Data的Web支持
Spring Data提供了Web支持,简化了Web应用程序中Spring Data存储库的使用。Spring Boot在spring.data.web
名称空间中提供了用于自定义其配置的属性。请注意,如果您使用的是Spring Data REST,则必须改为使用spring.data.rest
名称空间中的属性。
9.9.14。将Spring Data存储库公开为REST端点
如果已为应用程序启用了Spring MVC,则Spring Data REST可以为您将Repository实现公开为REST端点。
Spring Boot公开了一组有用的属性(来自spring.data.rest
名称空间),这些属性来自定义RepositoryRestConfiguration
。如果需要提供其他定制,则应使用RepositoryRestConfigurer
Bean。
如果您没有在自定义RepositoryRestConfigurer
上指定任何顺序,它将在Spring Boot内部使用的RepositoryRestConfigurer
之后运行。如果您需要指定订单,请确保该order大于0。
9.9.15。配置JPA使用的组件
如果要配置JPA使用的组件,则需要确保在JPA之前初始化该组件。当组件被自动配置后,Spring Boot会为您处理。例如,当自动配置Flyway时,会将Hibernate配置为依赖Flyway,以便Flyway有机会在Hibernate尝试使用数据库之前对其进行初始化。
如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor
子类作为设置必要依赖项的便捷方法。例如,如果将Hibernate Search与Elasticsearch一起用作其索引管理器,则EntityManagerFactory
必须将任何bean配置为依赖于elasticsearchClient
bean,如以下示例所示:
/**
* {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
* {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
*/
@Component
static class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
super("elasticsearchClient");
}
}
9.9.16。使用两个数据源配置jOOQ
如果需要将jOOQ与多个数据源一起使用,则应该为每个数据源创建自己的DSLContext
。有关更多详细信息,请参阅JooqAutoConfiguration
。
特别是,JooqExceptionTranslator
和SpringTransactionProvider
可以重复使用以对单个DataSource提供与自动配置相似的功能。