SQL 資料庫

Spring Framework 為使用 SQL 資料庫提供了廣泛的支援,從使用 JdbcClientJdbcTemplate 直接訪問 JDBC 到完整的“物件關係對映”技術,如 Hibernate。Spring Data 提供了額外的功能級別:直接從介面建立 Repository 實現,並使用約定從方法名稱生成查詢。

配置 DataSource

Java 的 DataSource 介面提供了一種使用資料庫連線的標準方法。傳統上,DataSource 使用 `URL` 和一些憑據來建立資料庫連線。

請參閱“操作指南”中的 配置自定義 DataSource 部分,瞭解更多高階示例,通常用於完全控制 DataSource 的配置。

嵌入式資料庫支援

使用記憶體嵌入式資料庫開發應用通常很方便。顯然,記憶體資料庫不提供持久儲存。您需要在應用啟動時填充資料庫,並在應用結束時準備好丟棄資料。

“操作指南”部分包含一個 關於如何初始化資料庫的章節

Spring Boot 可以自動配置嵌入式的 H2HSQLDerby 資料庫。您無需提供任何連線 URL。您只需包含所需使用的嵌入式資料庫的構建依賴項即可。如果 classpath 上存在多個嵌入式資料庫,請設定 `spring.datasource.embedded-database-connection` 配置屬性來控制使用哪個。將屬性設定為 `none` 將停用嵌入式資料庫的自動配置。

如果您在測試中使用此功能,您可能會注意到整個測試套件重複使用了同一個資料庫,無論您使用了多少個應用上下文。如果您想確保每個上下文都有一個單獨的嵌入式資料庫,您應該將 `spring.datasource.generate-unique-name` 設定為 `true`。

例如,典型的 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 來自動配置。

DataSource 配置

DataSource 配置由 `spring.datasource.*` 中的外部配置屬性控制。例如,您可以在 `application.properties` 中宣告以下部分:

  • 屬性檔案

  • YAML

spring.datasource.url=jdbc:mysql:///test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring:
  datasource:
    url: "jdbc:mysql:///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 連線池,您可以自定義許多其他設定,如下例所示:

  • 屬性檔案

  • 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

這將設定連線池在沒有可用連線時等待 10000ms,超過時間後丟擲異常;將最大連線數限制為 50;並在從連線池借用連線之前驗證連線。

支援的連線池

Spring Boot 使用以下演算法選擇特定的實現:

  1. 我們優先選擇 HikariCP,因為它具有卓越的效能和併發性。如果 HikariCP 可用,我們總是選擇它。

  2. 否則,如果 Tomcat 池化 DataSource 可用,我們就使用它。

  3. 否則,如果 Commons DBCP2 可用,我們就使用它。

  4. 如果 HikariCP、Tomcat 和 DBCP2 均不可用,而 Oracle UCP 可用,我們就使用它。

如果您使用 `spring-boot-starter-jdbc` 或 `spring-boot-starter-data-jpa` starter,您將自動獲得 HikariCP 的依賴。

您可以透過設定 `spring.datasource.type` 屬性完全繞過該演算法,並指定要使用的連線池。如果您在 Tomcat 容器中執行應用,這尤其重要,因為預設提供了 `tomcat-jdbc`。

始終可以使用 DataSourceBuilder 手動配置其他連線池。如果您定義自己的 DataSource bean,則不會發生自動配置。DataSourceBuilder 支援以下連線池:

連線到 JNDI DataSource

如果您將 Spring Boot 應用部署到應用伺服器,您可能希望使用應用伺服器的內建功能配置和管理您的 DataSource,並透過 JNDI 訪問它。

`spring.datasource.jndi-name` 屬性可以作為 `spring.datasource.url`、`spring.datasource.username` 和 `spring.datasource.password` 屬性的替代方案,用於從特定的 JNDI 位置訪問 DataSource。例如,`application.properties` 中的以下部分顯示瞭如何訪問 JBoss AS 定義的 DataSource

  • 屬性檔案

  • YAML

spring.datasource.jndi-name=java:jboss/datasources/customers
spring:
  datasource:
    jndi-name: "java:jboss/datasources/customers"

使用 JdbcTemplate

Spring 的 JdbcTemplateNamedParameterJdbcTemplate 類是自動配置的,您可以直接將它們自動注入到您自己的 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.*` 屬性來自定義模板的一些屬性,如下例所示:

  • 屬性檔案

  • YAML

spring.jdbc.template.max-rows=500
spring:
  jdbc:
    template:
      max-rows: 500
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 是一種標準技術,允許您將物件“對映”到關係資料庫。`spring-boot-starter-data-jpa` POM 提供了一種快速入門的方法。它提供了以下關鍵依賴項:

  • Hibernate:最流行的 JPA 實現之一。

  • Spring Data JPA:幫助您實現基於 JPA 的 Repository。

  • Spring ORM:Spring Framework 提供的核心 ORM 支援。

我們在此不詳細介紹 JPA 或 Spring Data。您可以按照 spring.io 上的 使用 JPA 訪問資料 指南,並閱讀 Spring Data JPAHibernate 參考文件。

實體類

傳統上,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 Repository

Spring Data JPA Repository 是您可以定義來訪問資料的介面。JPA 查詢會自動從您的方法名稱建立。例如,`CityRepository` 介面可以宣告一個 `findAllByState(String state)` 方法來查詢給定狀態的所有城市。

對於更復雜的查詢,您可以使用 Spring Data 的 Query 註解來標記您的方法。

Spring Data Repository 通常繼承自 RepositoryCrudRepository 介面。如果您使用自動配置,則會在自動配置包中搜索 Repository。

您可以使用 @EnableJpaRepositories 來自定義查詢 Repository 的位置。

以下示例顯示了一個典型的 Spring Data Repository 介面定義:

  • 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 Repository 支援三種不同的引導模式:default(預設)、deferred(延遲)和 lazy(懶載入)。要啟用延遲或懶載入引導,請分別將 `spring.data.jpa.repositories.bootstrap-mode` 屬性設定為 `deferred` 或 `lazy`。當使用延遲或懶載入引導時,自動配置的 EntityManagerFactoryBuilder 將使用上下文中的 AsyncTaskExecutor(如果存在)作為引導執行器。如果存在多個,將使用名稱為 `applicationTaskExecutor` 的執行器。

使用延遲或懶載入引導時,請確保在應用上下文引導階段之後再訪問 JPA 基礎設施。您可以使用 SmartInitializingSingleton 來呼叫任何需要 JPA 基礎設施的初始化。對於作為 Spring bean 建立的 JPA 元件(例如轉換器),如果存在依賴項,請使用 ObjectProvider 來延遲依賴項的解析。

我們對 Spring Data JPA 只做了初步的介紹。要獲取完整詳細資訊,請參閱 Spring Data JPA 參考文件

Spring Data Envers Repository

如果 Spring Data Envers 可用,則會自動配置 JPA Repository 以支援典型的 Envers 查詢。

要使用 Spring Data Envers,請確保您的 Repository 繼承自 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` 中:

  • 屬性檔案

  • 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 屬性的示例:
  • 屬性檔案

  • YAML

spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring:
  jpa:
    properties:
      hibernate:
        "globally_quoted_identifiers": "true"

前面示例中的行將 `hibernate.globally_quoted_identifiers` 屬性的值 `true` 傳遞給 Hibernate 實體管理器。

預設情況下,DDL 執行(或驗證)會延遲到 ApplicationContext 啟動後進行。

在 View 中開啟 EntityManager

如果您正在執行 Web 應用,Spring Boot 預設會註冊 OpenEntityManagerInViewInterceptor 來應用“在 View 中開啟 EntityManager”模式,以便在 Web 檢視中實現延遲載入。如果您不希望這種行為,您應該在 `application.properties` 中將 `spring.jpa.open-in-view` 設定為 `false`。

Spring Data JDBC

Spring Data 包含對 JDBC 的 Repository 支援,並將為 CrudRepository 上的方法自動生成 SQL。對於更高階的查詢,提供了 @Query 註解。

當 classpath 上存在必要的依賴項時,Spring Boot 會自動配置 Spring Data 的 JDBC Repository。您只需新增 `spring-boot-starter-data-jdbc` 依賴項即可將其新增到您的專案中。如有必要,您可以透過在應用中新增 @EnableJdbcRepositories 註解或 AbstractJdbcConfiguration 子類來控制 Spring Data JDBC 的配置。

有關 Spring Data JDBC 的完整詳細資訊,請參閱參考文件

使用 H2 的 Web 控制檯

[H2 資料庫] 提供了一個 基於瀏覽器的控制檯,Spring Boot 可以為您自動配置。滿足以下條件時,控制檯會自動配置:

如果您沒有使用 Spring Boot 的開發者工具,但仍然希望使用 H2 的控制檯,您可以透過將 `spring.h2.console.enabled` 屬性配置為 `true` 來實現。
H2 控制檯僅用於開發期間,因此您應該注意確保在生產環境中不要將 `spring.h2.console.enabled` 設定為 `true`。

更改 H2 控制檯的路徑

預設情況下,控制檯可在 `/h2-console` 訪問。您可以使用 `spring.h2.console.path` 屬性自定義控制檯的路徑。

在安全應用中訪問 H2 控制檯

H2 控制檯使用框架,並且僅用於開發,因此未實現 CSRF 防護措施。如果您的應用使用 Spring Security,您需要配置它以做到以下幾點:

  • 停用針對控制檯請求的 CSRF 防護,

  • 將控制檯響應中的 `X-Frame-Options` 頭部設定為 `SAMEORIGIN`。

有關 CSRFX-Frame-Options 頭部 的更多資訊,請查閱 Spring Security 參考指南。

在簡單設定中,可以使用如下所示的 SecurityFilterChain

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.security.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) throws Exception {
		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 防護或允許網站使用框架可能會造成嚴重的安全風險。
即使控制檯的路徑已自定義,`PathRequest.toH2Console()` 也會返回正確的請求匹配器。

使用 jOOQ

jOOQ Object Oriented Querying (jOOQ) 是 Data Geekery 的一款流行產品,它可以根據您的資料庫生成 Java 程式碼,並透過其流暢的 API 構建型別安全的 SQL 查詢。商業版和開源版都可以與 Spring Boot 一起使用。

程式碼生成

為了使用 jOOQ 的型別安全查詢,您需要根據資料庫 schema 生成 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 之前進行更高階的定製。這優先於自動配置應用的任何內容。

如果您想完全控制 jOOQ 配置,也可以建立自己的 Configuration @Bean

使用 R2DBC

反應式關係資料庫連線 (R2DBC) 專案為關係資料庫帶來了反應式程式設計 API。R2DBC 的 Connection 提供了一種處理非阻塞資料庫連線的標準方法。連線是透過使用 ConnectionFactory 提供的,類似於 JDBC 的 DataSource

ConnectionFactory 的配置由 spring.r2dbc.* 中的外部配置屬性控制。例如,您可以在 application.properties 中宣告以下部分

  • 屬性檔案

  • YAML

spring.r2dbc.url=r2dbc:postgresql:///test
spring.r2dbc.username=dbuser
spring.r2dbc.password=dbpass
spring:
  r2dbc:
    url: "r2dbc:postgresql:///test"
    username: "dbuser"
    password: "dbpass"
您無需指定驅動類名稱,因為 Spring Boot 會從 R2DBC 的 Connection Factory 發現機制中獲取驅動。
至少需要提供 url。URL 中指定的資訊優先於單個屬性,即 nameusernamepassword 和連線池選項。
“How-to Guides” 部分包含關於如何初始化資料庫的部分。

要定製由 ConnectionFactory 建立的連線,即設定您不想(或不能)在中央資料庫配置中配置的特定引數,您可以使用 ConnectionFactoryOptionsBuilderCustomizer @Bean。以下示例演示瞭如何在其餘選項取自應用程式配置的情況下手動覆蓋資料庫埠

  • Java

  • Kotlin

import io.r2dbc.spi.ConnectionFactoryOptions;

import org.springframework.boot.autoconfigure.r2dbc.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.autoconfigure.r2dbc.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.autoconfigure.r2dbc.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.autoconfigure.r2dbc.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>

如果您在測試中使用此功能,您可能會注意到整個測試套件會重用同一個資料庫,無論您使用了多少個應用程式上下文。如果您想確保每個上下文都有一個單獨的嵌入式資料庫,應將 spring.r2dbc.generate-unique-name 設定為 true

使用 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 Repositories

Spring Data R2DBC repositories 是您可以定義用於訪問資料的介面。查詢是根據方法名稱自動建立的。例如,CityRepository 介面可以宣告一個 findAllByState(String state) 方法來查詢給定狀態中的所有城市。

對於更復雜的查詢,您可以使用 Spring Data 的 @Query 註解來註解您的方法。

Spring Data Repository 通常繼承自 RepositoryCrudRepository 介面。如果您使用自動配置,則會在自動配置包中搜索 Repository。

以下示例顯示了一個典型的 Spring Data Repository 介面定義:

  • 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 參考文件