|
此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Boot 4.0.4! |
SQL 数据库
Spring 框架 提供了对 SQL 数据库的广泛支持,既包括使用 JdbcClient 或 JdbcTemplate 进行的直接 JDBC 访问,也涵盖 Hibernate 等完整的“对象关系映射”(ORM)技术。
Spring Data 提供了更进一步的功能:可直接从接口创建 Repository 实现,并通过约定根据方法名称自动生成查询。
配置数据源
Java 的 DataSource 接口提供了一种标准的数据库连接操作方法。
传统上,DataSource 会使用 URL 及一些凭据来建立数据库连接。
| 请参阅“操作指南”中的配置自定义数据源章节,以获取更高级的示例,这些示例通常用于完全掌控数据源的配置。 |
嵌入式数据库支持
使用内存嵌入式数据库来开发应用程序通常十分便捷。 显然,内存数据库无法提供持久化存储。 您需要在应用程序启动时填充数据库,并准备好在应用程序结束时丢弃数据。
| “操作指南”部分包含一个关于如何初始化数据库的章节。 |
Spring Boot 可以自动配置嵌入式 H2、HSQL 和 Derby(已弃用)数据库。
您无需提供任何连接 URL。
您只需包含要使用的嵌入式数据库的构建依赖项。
如果类路径上有多个嵌入式数据库,请将 spring.datasource.embedded-database-connection 配置属性设置为控制使用哪一个。
将该属性设置为 none 会禁用嵌入式数据库的自动配置。
|
如果您在测试中使用此功能,可能会注意到,无论您使用多少个应用上下文,整个测试套件都会重复使用同一个数据库。
如果您希望确保每个上下文都拥有独立的嵌入式数据库,则应将 |
例如,典型的 POM 依赖项如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
要自动配置嵌入式数据库,您需要依赖 spring-jdbc。
在此示例中,该依赖通过 spring-boot-starter-data-jpa 间接引入。 |
出于任何原因,若您为嵌入式数据库配置了连接URL,请务必确保禁用该数据库的自动关闭功能。
若使用 H2 数据库,应通过设置为 DB_CLOSE_ON_EXIT=FALSE 来实现此目的。
若使用 HSQLDB 数据库,则应确保不使用 shutdown=true。
禁用数据库的自动关闭功能可使 Spring Boot 控制数据库的关闭时机,从而确保数据库仅在不再需要访问时才被关闭。 |
连接到生产数据库
生产环境数据库连接也可以通过使用连接池化的 DataSource 自动配置。
数据源配置
数据源配置由 spring.datasource.* 中的外部配置属性控制。
例如,您可以在 application.properties 中声明以下配置段:
-
Properties
-
YAML
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
您至少应通过设置 spring.datasource.url 属性来指定 URL。
否则,Spring Boot 将尝试自动配置嵌入式数据库。 |
Spring Boot 可根据大多数数据库的 URL 推断出 JDBC 驱动程序类。
如果需要指定特定的类,可以使用 spring.datasource.driver-class-name 属性。 |
要创建一个连接池化的 DataSource,我们需要能够验证一个有效的 Driver 类是否可用,因此我们会在执行任何操作之前先进行该检查。
换言之,如果您设置了 spring.datasource.driver-class-name=com.mysql.jdbc.Driver,则该类必须能够被成功加载。 |
请参阅 DataSourceProperties 的 API 文档,了解所支持的更多选项。
这些是标准选项,无论采用何种 实际实现 均可使用。
您还可以通过各自对应的前缀(spring.datasource.hikari.*、spring.datasource.tomcat.*、spring.datasource.dbcp2.* 和 spring.datasource.oracleucp.*)来微调特定于实现的设置。
有关更多详细信息,请参阅您所使用的连接池实现的文档。
例如,如果您使用 Tomcat 连接池,则可以自定义许多其他设置,如下例所示:
-
Properties
-
YAML
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.test-on-borrow=true
spring:
datasource:
tomcat:
max-wait: 10000
max-active: 50
test-on-borrow: true
这将设置连接池在无可用连接时等待 10000 毫秒后抛出异常,将最大连接数限制为 50,并在从连接池中借用连接之前验证该连接。
支持的连接池
Spring Boot 使用以下算法来选择特定的实现:
-
我们首选 HikariCP,因其出色的性能和并发处理能力。 如果 HikariCP 可用,我们将始终选择它。
-
否则,如果 Tomcat 连接池
DataSource可用,则使用它。 -
否则,如果Commons DBCP2可用,我们将使用它。
-
如果 HikariCP、Tomcat 和 DBCP2 均不可用,而 Oracle UCP 可用,则使用 Oracle UCP。
如果您使用 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa 起步依赖,将自动引入 HikariCP 依赖。 |
您可以完全绕过该算法,并通过设置 spring.datasource.type 属性来指定要使用的连接池。
如果您在 Tomcat 容器中运行应用程序,这一点尤为重要,因为默认情况下会提供 tomcat-jdbc。
您始终可以手动配置额外的连接池,方法是使用 DataSourceBuilder。
如果您自行定义了 DataSource Bean,则不会触发自动配置。
以下连接池受 DataSourceBuilder 支持:
-
HikariCP
-
Tomcat 连接池
DataSource -
Commons DBCP2
-
Oracle UCP 与
OracleDataSource -
Spring 框架的
SimpleDriverDataSource -
PostgreSQL
PGSimpleDataSource -
C3P0
-
Vibur
连接到 JNDI 数据源
如果将 Spring Boot 应用程序部署到应用服务器中,您可能希望利用该应用服务器的内置功能来配置和管理 DataSource,并通过 JNDI 进行访问。
spring.datasource.jndi-name 属性可作为 spring.datasource.url、spring.datasource.username 和 spring.datasource.password 属性的替代方案,用于从特定 JNDI 位置访问 DataSource。
例如,application.properties 中的以下部分展示了如何访问 JBoss AS 定义的 DataSource:
-
Properties
-
YAML
spring.datasource.jndi-name=java:jboss/datasources/customers
spring:
datasource:
jndi-name: "java:jboss/datasources/customers"
使用 JdbcTemplate
Spring 的 JdbcTemplate 和 NamedParameterJdbcTemplate 类已自动配置,您可以直接将它们自动装配到您自己的 Bean 中,如下例所示:
-
Java
-
Kotlin
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JdbcTemplate jdbcTemplate;
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void doSomething() {
this.jdbcTemplate ...
}
}
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Component
@Component
class MyBean(private val jdbcTemplate: JdbcTemplate) {
fun doSomething() {
jdbcTemplate.execute("delete from customer")
}
}
您可以通过使用 spring.jdbc.template.* 属性来自定义模板的某些属性,如下例所示:
-
Properties
-
YAML
spring.jdbc.template.max-rows=500
spring:
jdbc:
template:
max-rows: 500
如果需要调整 SQL 异常处理,您可以定义自己的 SQLExceptionTranslator Bean,使其与自动配置的 JdbcTemplate 关联。
NamedParameterJdbcTemplate 在后台重用了同一个 JdbcTemplate 实例。
如果定义了多个 JdbcTemplate 且不存在主候选者,则不会自动配置 NamedParameterJdbcTemplate。 |
使用 JdbcClient
Spring 的 JdbcClient 会根据是否存在 NamedParameterJdbcTemplate 进行自动配置。
您也可以像以下示例所示,直接将其注入到您自己的 Bean 中:
-
Java
-
Kotlin
import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JdbcClient jdbcClient;
public MyBean(JdbcClient jdbcClient) {
this.jdbcClient = jdbcClient;
}
public void doSomething() {
this.jdbcClient ...
}
}
import org.springframework.jdbc.core.simple.JdbcClient
import org.springframework.stereotype.Component
@Component
class MyBean(private val jdbcClient: JdbcClient) {
fun doSomething() {
jdbcClient.sql("delete from customer").update()
}
}
如果您依赖自动配置来创建底层的 JdbcTemplate,则使用 spring.jdbc.template.* 属性进行的任何自定义也会在客户端中生效。
JPA 与 Spring Data JPA
Java 持久化 API(JPA)是一项标准技术,允许您将对象“映射”到关系型数据库。
spring-boot-starter-data-jpa POM 提供了一种快速入门的方式。
它提供了以下关键依赖项:
-
Hibernate:最流行的 JPA 实现之一。
-
Spring Data JPA:帮助您实现基于 JPA 的仓库(Repository)。
-
Spring ORM:Spring 框架提供的核心 ORM 支持。
| 此处我们不会深入探讨 JPA 或 Spring Data 的过多细节。 您可以参考 使用 JPA 访问数据 指南(来自 spring.io),并阅读 Spring Data JPA 和 Hibernate 的参考文档。 |
实体类
传统上,JPA“实体”类在persistence.xml文件中指定。
使用Spring Boot时,该文件不再是必需的,而是采用“实体扫描”机制。
默认情况下,会扫描自动配置包。
任何使用 @Entity、@Embeddable 或 @MappedSuperclass 注解的类均被视为符合条件。
典型的实体类如下例所示:
-
Java
-
Kotlin
import java.io.Serializable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class City implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
// ... additional members, often include @OneToMany mappings
protected City() {
// no-args constructor required by JPA spec
// this one is protected since it should not be used directly
}
public City(String name, String state) {
this.name = name;
this.state = state;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
// ... etc
}
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
import java.io.Serializable
@Entity
class City : Serializable {
@Id
@GeneratedValue
private val id: Long? = null
@Column(nullable = false)
var name: String? = null
private set
// ... etc
@Column(nullable = false)
var state: String? = null
private set
// ... additional members, often include @OneToMany mappings
protected constructor() {
// no-args constructor required by JPA spec
// this one is protected since it should not be used directly
}
constructor(name: String?, state: String?) {
this.name = name
this.state = state
}
}
您可以使用 @EntityScan 注解来自定义实体扫描位置。
请参阅“操作指南”中的“将 @Entity 定义与 Spring 配置分离”一节。 |
Spring Data JPA 仓库
Spring Data JPA 仓库是您可定义的接口,用于访问数据。
JPA 查询会根据您的方法名称自动生成。
例如,一个 CityRepository 接口可能声明一个 findAllByState(String state) 方法,以查找指定州内的所有城市。
对于更复杂的查询,您可以使用 Spring Data 的 Query 注解来标注您的方法。
Spring Data 仓库通常继承自 Repository 或 CrudRepository 接口。
如果使用自动配置,则会在 自动配置包 中搜索仓库。
您可以使用 @EnableJpaRepositories 自定义查找仓库的位置。 |
以下示例展示了一个典型的 Spring Data 仓库接口定义:
-
Java
-
Kotlin
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
}
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.Repository
interface CityRepository : Repository<City, Long> {
fun findAll(pageable: Pageable?): Page<City>?
fun findByNameAndStateAllIgnoringCase(name: String?, state: String?): City?
}
Spring Data JPA 仓库支持三种不同的启动模式:默认模式、延迟模式和懒加载模式。
要启用延迟模式或懒加载模式,请分别将 spring.data.jpa.repositories.bootstrap-mode 属性设置为 deferred 或 lazy。
在使用延迟模式或懒加载模式时,自动配置的 EntityManagerFactoryBuilder 将使用上下文中的 AsyncTaskExecutor(如果存在)作为启动执行器。
如果存在多个,则使用名称为 applicationTaskExecutor 的那个。
|
使用延迟或懒加载启动方式时,请确保在应用上下文启动阶段之后再访问 JPA 基础设施。
您可以使用 |
| 我们仅初步了解了 Spring Data JPA 的基本功能。 如需完整详情,请参阅 Spring Data JPA 参考文档。 |
Spring Data Envers 仓库
如果 Spring Data Envers 可用,则会自动配置 JPA 仓库以支持典型的 Envers 查询。
要使用 Spring Data Envers,请确保您的仓库接口继承自 RevisionRepository,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.history.RevisionRepository;
public interface CountryRepository extends RevisionRepository<Country, Long, Integer>, Repository<Country, Long> {
Page<Country> findAll(Pageable pageable);
}
import org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.Repository
import org.springframework.data.repository.history.RevisionRepository
interface CountryRepository :
RevisionRepository<Country, Long, Int>,
Repository<Country, Long> {
fun findAll(pageable: Pageable?): Page<Country>?
}
| 如需了解详细信息,请参阅 Spring Data Envers 参考文档。 |
创建和删除 JPA 数据库
默认情况下,仅当使用嵌入式数据库(即 H2、HSQL 或 Derby(已弃用))时,JPA 数据库才会自动创建。
您可以通过使用 spring.jpa.* 属性显式配置 JPA 设置。
例如,要创建和删除表,可以将以下行添加到您的 application.properties 中:
-
Properties
-
YAML
spring.jpa.hibernate.ddl-auto=create-drop
spring:
jpa:
hibernate.ddl-auto: "create-drop"
Hibernate 自身用于此功能的内部属性名称(如果您对此名称更熟悉)为 hibernate.hbm2ddl.auto。
您可以通过使用 spring.jpa.properties.* 来设置该属性以及其他 Hibernate 原生属性(在将其添加到实体管理器之前,会自动移除前缀)。
以下代码行展示了为 Hibernate 设置 JPA 属性的示例: |
-
Properties
-
YAML
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring:
jpa:
properties:
hibernate:
"globally_quoted_identifiers": "true"
上例中的代码行向 Hibernate 实体管理器传递了 hibernate.globally_quoted_identifiers 属性的值 true。
默认情况下,DDL 执行(或验证)将延迟到 ApplicationContext 启动后进行。
在视图中打开 EntityManager
如果您正在运行一个 Web 应用程序,Spring Boot 默认会注册 OpenEntityManagerInViewInterceptor,以启用“Open EntityManager in View”(在视图中保持 EntityManager 打开)模式,从而允许在 Web 视图中进行延迟加载。
如果您不希望启用此行为,则应在您的 application.properties 中将 spring.jpa.open-in-view 设置为 false。
Spring Data JDBC
Spring Data 包含对 JDBC 的仓库支持,并会自动为 CrudRepository 接口上的方法生成 SQL。
对于更复杂的查询,提供了 @Query 注解。
当必要的依赖项位于类路径中时,Spring Boot 会自动配置 Spring Data 的 JDBC 仓库。
您只需在项目中添加一个对 spring-boot-starter-data-jdbc 的依赖即可引入这些功能。
如有必要,您可以通过在应用程序中添加 @EnableJdbcRepositories 注解或 AbstractJdbcConfiguration 子类来接管 Spring Data JDBC 的配置。
如果您使用 Spring Data JDBC 与 提前处理(针对 JVM 或原生映像),建议进行一些额外的配置。
为了在 AOT 处理期间避免需要数据库连接,请定义一个适用于您应用程序数据库的 JdbcDialect Bean。
例如,如果您使用的是 Postgres,请定义一个 JdbcPostgresDialect Bean。
| 有关 Spring Data JDBC 的完整详细信息,请参阅 参考文档。 |
使用 H2 的 Web 控制台
-
您正在开发一个基于 Servlet 的 Web 应用程序。
-
org.springframework.boot:spring-boot-h2console位于类路径中。 -
您正在使用 Spring Boot 的开发者工具。
如果您未使用 Spring Boot 的开发者工具,但仍希望使用 H2 的控制台,则可以将 spring.h2.console.enabled 属性配置为 true。 |
H2 控制台仅用于开发阶段,因此请务必确保在生产环境中未将 spring.h2.console.enabled 设置为 true。 |
在受保护的应用程序中访问 H2 控制台
H2 控制台使用框架(frames),且仅用于开发目的,因此未实现 CSRF 防护措施。 如果您的应用程序使用 Spring Security,则需要对其进行相应配置:
-
为针对控制台的请求禁用 CSRF 保护,
-
将控制台响应的请求头
X-Frame-Options设置为SAMEORIGIN。
有关 CSRF 和请求头 X-Frame-Options 的更多信息,请参阅《Spring Security 参考指南》。
在简单配置中,可以使用如下所示的 SecurityFilterChain:
-
Java
-
Kotlin
import org.springframework.boot.security.autoconfigure.web.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
import org.springframework.security.web.SecurityFilterChain;
@Profile("dev")
@Configuration(proxyBeanMethods = false)
public class DevProfileSecurityConfiguration {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) {
http.securityMatcher(PathRequest.toH2Console());
http.authorizeHttpRequests(yourCustomAuthorization());
http.csrf(CsrfConfigurer::disable);
http.headers((headers) -> headers.frameOptions(FrameOptionsConfig::sameOrigin));
return http.build();
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.security.config.Customizer
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain
@Profile("dev")
@Configuration(proxyBeanMethods = false)
class DevProfileSecurityConfiguration {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
fun h2ConsoleSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
return http.authorizeHttpRequests(yourCustomAuthorization())
.csrf { csrf -> csrf.disable() }
.headers { headers -> headers.frameOptions { frameOptions -> frameOptions.sameOrigin() } }
.build()
}
}
| H2 控制台仅用于开发阶段。 在生产环境中,禁用 CSRF 保护或允许网站使用框架(frames)可能会带来严重的安全风险。 |
PathRequest.toH2Console() 在控制台路径已被自定义的情况下,也能返回正确的请求匹配器。 |
使用 jOOQ
jOOQ 面向对象查询(jOOQ)是由 Data Geekery 提供的一个流行产品,它可以从您的数据库生成 Java 代码,并通过其流畅的 API 让您构建类型安全的 SQL 查询。 商业版和开源版都可以与 Spring Boot 一起使用。 jOOQ 需要 Java 21 或更高版本。
代码生成
如需使用 jOOQ 的类型安全查询,您需要根据数据库模式生成 Java 类。
您可以参考 jOOQ 用户手册 中的说明。
如果您使用了 jooq-codegen-maven 插件,并且同时使用了 spring-boot-starter-parent “父 POM”,则可以安全地省略该插件的 <version> 标签。
您还可以使用 Spring Boot 定义的版本变量(例如 h2.version)来声明该插件的数据库依赖项。
以下示例展示了具体用法:
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
...
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
...
</generator>
</configuration>
</plugin>
使用 DSLContext
jOOQ 提供的流畅式 API 通过 DSLContext 接口启动。
Spring Boot 会自动配置一个 DSLContext 作为 Spring Bean,并将其连接到您的应用程序 DataSource。
要使用 DSLContext,您可以按以下示例所示的方式注入它:
-
Java
-
Kotlin
import java.util.GregorianCalendar;
import java.util.List;
import org.jooq.DSLContext;
import org.springframework.stereotype.Component;
import static org.springframework.boot.docs.data.sql.jooq.dslcontext.Tables.AUTHOR;
@Component
public class MyBean {
private final DSLContext create;
public MyBean(DSLContext dslContext) {
this.create = dslContext;
}
}
import org.jooq.DSLContext
import org.springframework.stereotype.Component
import java.util.GregorianCalendar
@Component
class MyBean(private val create: DSLContext) {
}
jOOQ 手册通常使用名为 create 的变量来保存 DSLContext。 |
然后,您可以使用 DSLContext 来构建查询,如下例所示:
-
Java
-
Kotlin
public List<GregorianCalendar> authorsBornAfter1980() {
return this.create.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
.fetch(AUTHOR.DATE_OF_BIRTH);
fun authorsBornAfter1980(): List<GregorianCalendar> {
return create.selectFrom<Tables.TAuthorRecord>(Tables.AUTHOR)
.where(Tables.AUTHOR?.DATE_OF_BIRTH?.greaterThan(GregorianCalendar(1980, 0, 1)))
.fetch(Tables.AUTHOR?.DATE_OF_BIRTH)
}
jOOQ SQL 方言
除非已配置 spring.jooq.sql-dialect 属性,否则 Spring Boot 将根据您的数据源自动确定要使用的 SQL 方言。
如果 Spring Boot 无法检测到方言,则默认使用 DEFAULT。
| Spring Boot 仅能自动配置 jOOQ 开源版本所支持的方言。 |
自定义 jOOQ
通过定义您自己的 DefaultConfigurationCustomizer Bean,可在创建 Configuration @Bean 之前调用该 Bean,从而实现更高级的自定义配置。
此配置的优先级高于自动配置所应用的任何设置。
您也可以创建自己的 Configuration @Bean,以便完全掌控 jOOQ 的配置。
使用 R2DBC
响应式关系型数据库连接(R2DBC)项目为关系型数据库引入了响应式编程 API。
R2DBC 的 Connection 提供了一种标准方法,用于处理非阻塞式数据库连接。
连接通过使用 ConnectionFactory 来提供,其方式类似于使用 JDBC 的 DataSource。
ConnectionFactory 配置由 spring.r2dbc.* 中的外部配置属性控制。
例如,您可以在 application.properties 中声明以下配置段:
-
Properties
-
YAML
spring.r2dbc.url=r2dbc:postgresql://localhost/test
spring.r2dbc.username=dbuser
spring.r2dbc.password=dbpass
spring:
r2dbc:
url: "r2dbc:postgresql://localhost/test"
username: "dbuser"
password: "dbpass"
| 您无需指定驱动程序类名称,因为 Spring Boot 会从 R2DBC 的连接工厂发现机制中获取驱动程序。 |
至少必须提供 URL。
URL 中指定的信息优先于各个独立属性(即 name、username、password 以及连接池选项)。 |
| “操作指南”部分包含一个关于如何初始化数据库的章节。 |
如需自定义由 ConnectionFactory 创建的连接(即设置您不希望(或无法)在中心数据库配置中进行配置的特定参数),您可以使用 ConnectionFactoryOptionsBuilderCustomizer @Bean。
以下示例展示了如何手动覆盖数据库端口,而其余选项则从应用程序配置中获取:
-
Java
-
Kotlin
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyR2dbcConfiguration {
@Bean
public ConnectionFactoryOptionsBuilderCustomizer connectionFactoryPortCustomizer() {
return (builder) -> builder.option(ConnectionFactoryOptions.PORT, 5432);
}
}
import io.r2dbc.spi.ConnectionFactoryOptions
import org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
class MyR2dbcConfiguration {
@Bean
fun connectionFactoryPortCustomizer(): ConnectionFactoryOptionsBuilderCustomizer {
return ConnectionFactoryOptionsBuilderCustomizer { builder ->
builder.option(ConnectionFactoryOptions.PORT, 5432)
}
}
}
以下示例展示了如何设置一些 PostgreSQL 连接选项:
-
Java
-
Kotlin
import java.util.HashMap;
import java.util.Map;
import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider;
import org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyPostgresR2dbcConfiguration {
@Bean
public ConnectionFactoryOptionsBuilderCustomizer postgresCustomizer() {
Map<String, String> options = new HashMap<>();
options.put("lock_timeout", "30s");
options.put("statement_timeout", "60s");
return (builder) -> builder.option(PostgresqlConnectionFactoryProvider.OPTIONS, options);
}
}
import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider
import org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
class MyPostgresR2dbcConfiguration {
@Bean
fun postgresCustomizer(): ConnectionFactoryOptionsBuilderCustomizer {
val options: MutableMap<String, String> = HashMap()
options["lock_timeout"] = "30s"
options["statement_timeout"] = "60s"
return ConnectionFactoryOptionsBuilderCustomizer { builder ->
builder.option(PostgresqlConnectionFactoryProvider.OPTIONS, options)
}
}
}
当存在一个 ConnectionFactory Bean 时,常规的 JDBC DataSource 自动配置将自动退出。
如果您希望保留 JDBC DataSource 自动配置,并且能够接受在响应式应用程序中使用阻塞式 JDBC API 所带来的风险,请在应用程序中的某个 @Configuration 类上添加 @Import(DataSourceAutoConfiguration.class),以重新启用该配置。
嵌入式数据库支持
与JDBC 支持类似,Spring Boot 可自动为响应式使用场景配置嵌入式数据库。 您无需提供任何连接 URL。 您只需在构建依赖中包含所需使用的嵌入式数据库,如下例所示:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
|
如果您在测试中使用此功能,可能会注意到,无论您使用多少个应用上下文,整个测试套件都会重复使用同一个数据库。
如果您希望确保每个上下文都拥有独立的嵌入式数据库,则应将 |
使用 DatabaseClient
会自动配置一个 DatabaseClient Bean,您可以直接将其自动装配到您自己的 Bean 中,如下例所示:
-
Java
-
Kotlin
import java.util.Map;
import reactor.core.publisher.Flux;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final DatabaseClient databaseClient;
public MyBean(DatabaseClient databaseClient) {
this.databaseClient = databaseClient;
}
// ...
public Flux<Map<String, Object>> someMethod() {
return this.databaseClient.sql("select * from user").fetch().all();
}
}
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.stereotype.Component
import reactor.core.publisher.Flux
@Component
class MyBean(private val databaseClient: DatabaseClient) {
// ...
fun someMethod(): Flux<Map<String, Any>> {
return databaseClient.sql("select * from user").fetch().all()
}
}
Spring Data R2DBC 仓库
Spring Data R2DBC 仓库是您可定义的接口,用于访问数据。
查询会根据您的方法名称自动生成。
例如,一个 CityRepository 接口可能声明一个 findAllByState(String state) 方法,以查找指定州内的所有城市。
对于更复杂的查询,您可以使用 Spring Data 的 @Query 注解来标注您的方法。
Spring Data 仓库通常继承自 Repository 或 CrudRepository 接口。
如果使用自动配置,则会在 自动配置包 中搜索仓库。
以下示例展示了一个典型的 Spring Data 仓库接口定义:
-
Java
-
Kotlin
import reactor.core.publisher.Mono;
import org.springframework.data.repository.Repository;
public interface CityRepository extends Repository<City, Long> {
Mono<City> findByNameAndStateAllIgnoringCase(String name, String state);
}
import org.springframework.data.repository.Repository
import reactor.core.publisher.Mono
interface CityRepository : Repository<City, Long> {
fun findByNameAndStateAllIgnoringCase(name: String, state: String): Mono<City>
}
| 我们仅初步了解了 Spring Data R2DBC 的基本功能。如需完整详情,请参阅 Spring Data R2DBC 参考文档。 |