Проект Reactive Relational Database Connectivity (R2DBC) привносит API реактивного программирования в реляционные базы данных. io.r2dbc.spi.Connection
из R2DBC предусматривает стандартный метод работы с неблокирующими подключениями к базе данных. Подключения передаются с помощью ConnectionFactory
, аналогично DataSource
в jdbc.
Конфигурацией ConnectionFactory
управляют внешние конфигурационные свойства из spring.r2dbc.*
. Например, можно объявить следующий раздел в application.properties
:
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"
name
, username
, password
и параметрами объединения в пул.Чтобы настроить соединения, создаваемые ConnectionFactory
, то есть задать определенные параметры, которые вы не желаете (или не можете) настраивать в конфигурации вашей центральной базы данных, можно использовать помеченный аннотацией @Bean
бин ConnectionFactoryOptionsBuilderCustomizer
. В следующем примере показано, как вручную переопределить порт базы данных, в то время как остальные параметры будут браться из конфигурации приложения:
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:
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
, обычная автоконфигурация для 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
непосредственно к своим собственным бинам, как это показано в следующем примере:
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)
для поиска всех городов в данном штате.
В случае более сложных запросов можно аннотировать метод с помощью аннотации Query
из Spring Data.
Репозитории Spring Data обычно расширяются за счет интерфейсов Repository
или CrudRepository
. Если вы используете автоконфигурацию, поиск в репозиториях ведется от пакета, содержащего основной конфигурационный класс (тот, который аннотирован @EnableAutoConfiguration
или @SpringBootApplication
), и вниз по иерархии.
В следующем примере показано типичное определение интерфейса взаимодействия с репозиторием Spring Data:
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?>?
}