Проект Reactive Relational Database Connectivity (R2DBC) привносить API реактивного програмування до реляційних баз даних. io.r2dbc.spi.Connection з R2DBC передбачає стандартний метод роботи з неблокуючими підключеннями до бази даних. З'єднання передаються за допомогою ConnectionFactory, аналогічно DataSource в jdbc.

Конфігурацією ConnectionFactory керують зовнішні конфігураційні властивості з spring.r2dbc.*. Наприклад, можна оголосити наступний розділ у application.properties:

Properties
spring.r2dbc.url=r2dbc:postgresql://localhost/test
spring.r2dbc.username=dbuser
spring.r2dbc.password=dbpass
Yaml
spring:
  r2dbc:
    url: "r2dbc:postgresql://localhost/test"
    username: "dbuser"
    password: "dbpass"
Вказувати ім'я класу для драйвера не потрібно, оскільки Spring Boot отримує драйвер в результаті виявлення фабрики з'єднань R2DBC.
Принаймні, має бути вказана URL-адреса. Інформація, вказана в URL-адресі, має пріоритет над окремими властивостями, тобто name, username, password та параметрами об'єднання в пул.

Щоб налаштувати з'єднання, що створюються ConnectionFactory, тобто зазначити певні параметри, які ти не бажаєш (або не можеш) налаштовувати в конфігурації твоєї центральної бази даних, можна використовувати позначений анотацією @Bean бін ConnectionFactoryOptionsBuilderCustomizer. У цьому прикладі показано, як вручну перевизначити порт бази даних, тоді як інші параметри будуть братися з конфігурації програми:

Java
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);
    }
}
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)
class MyR2dbcConfiguration {
    @Bean
    fun connectionFactoryPortCustomizer(): ConnectionFactoryOptionsBuilderCustomizer {
        return ConnectionFactoryOptionsBuilderCustomizer { builder ->
            builder.option(ConnectionFactoryOptions.PORT, 5432)
        }
    }
}

У наступних прикладах показано, як встановити певні параметри з'єднання PostgreSQL:

Java
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);
    }
}
Kotlin
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, звичайна автоконфігурація для DataSource з JDBC відключається. Якщо необхідно зберегти автоконфігурацію для DataSource з JDBC, і водночас тебе влаштовує ризик використання блокуючого JDBC API в реактивному додатку, додай @Import(DataSourceAutoConfiguration.class) до класу, позначеного анотацією @Configuration у своїй програмі, щоб повторно активувати її.

Підтримка вбудованих баз даних

Аналогічно засобам підтримки 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 є конфігурованим, але ти можеш прив'язати його через анотацію @Autowire безпосередньо до власних бінів, як це показано в наступному прикладі:

Java
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();
    }
}
Kotlin
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) для пошуку всіх міст у цьому штаті.

У разі більш складних запитів можна анотувати метод за допомогою анотації Query із Spring Data.

Репозиторії Spring Data зазвичай розширюються за рахунок інтерфейсів Repository або CrudRepository. Якщо ти використовуєг автоконфігурацію, пошук в репозиторіях ведеться від пакета, що містить основний клас конфігурації (той, який анотований @EnableAutoConfiguration або @SpringBootApplication), і вниз за ієрархією.

У наступному прикладі показано типове визначення інтерфейсу взаємодії з репозиторієм Spring Data:

Java
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);
}
Kotlin
import org.springframework.data.repository.Repository
import reactor.core.publisher.Mono
interface CityRepository : Repository<City?, Long?> {
    fun findByNameAndStateAllIgnoringCase(name: String?, state: String?): Mono<City?>?
}