The Reactive Relational Database Connectivity project (R2DBC) brings the reactive programming API to relational databases. io.r2dbc.spi.Connection
from R2DBC provides a standard method for dealing with non-blocking database connections. Connections are passed using ConnectionFactory
, similar to DataSource
in jdbc.
The ConnectionFactory
configuration is controlled by external configuration properties from spring.r2dbc.*
. For example, you could declare the following section in 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
, and pooling parameters.
To customize the connections created by the ConnectionFactory
, that is, to set certain parameters that you do not want (or cannot) configure in your central database configuration, you can use a @Bean
bean ConnectionFactoryOptionsBuilderCustomizer
. The following example shows how to manually override the database port while the rest of the settings are taken from the application configuration:
@Configuration(proxyBeanMethods = false) public class MyR2dbcConfiguration { @Bean public ConnectionFactoryOptionsBuilderCustomizer connectionFactoryPortCustomizer() { return (builder) -> builder.option(ConnectionFactoryOptions.PORT, 5432); } }
@Configuration(proxyBeanMethods = false) class MyR2dbcConfiguration { @Bean fun connectionFactoryPortCustomizer(): ConnectionFactoryOptionsBuilderCustomizer { return ConnectionFactoryOptionsBuilderCustomizer { builder -> builder.option(ConnectionFactoryOptions.PORT, 5432) } } }
The following examples show how to set some PostgreSQL connection parameters:
@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); } }
@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) } } }
If a ConnectionFactory
bean is present, normal auto-configuration for DataSource
from JDBC is disabled. If you need to preserve auto-configuration for DataSource
from JDBC, and are comfortable with the risk of using a blocking JDBC API in a reactive application, add @Import(DataSourceAutoConfiguration.class)
to the class marked with the annotation @Configuration
, in your application to re-enable it.
Support for embedded databases
Similar to JDBC support, the Spring Boot framework can automatically configure the embedded database for reactive use. You do not need to provide any connection URLs. You only need to add a build dependency to the embedded database you want to use, as shown in the following example:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
If you use this feature in your tests, you may notice that the same database is reused by your entire test suite, regardless of the number of application contexts you use. If you need to ensure that each context has a separate embedded database, you should set spring.r2dbc.generate-unique-name
to true
.
Using DatabaseClient
The DatabaseClient
bean is auto-configurable, but you can bind it via the @Autowire
annotation directly to your own beans, as shown in the following example:
@Component public class MyBean { private final DatabaseClient databaseClient; public MyBean(DatabaseClient databaseClient) { this.databaseClient = databaseClient; } }
@Component class MyBean(private val databaseClient: DatabaseClient) { }
Spring Data R2DBC Repositories
Spring Data R2DBC repositories are interfaces that can be defined to access data. Queries are created automatically based on method names. For example, the CityRepository
interface might declare a findAllByState(String state)
method to find all cities in a given state.
For more complex queries, you can annotate the method using the Query
annotation from Spring Data.
Spring Data repositories are typically extended using the Repository
or CrudRepository
interfaces. If you use auto-configuration, the repositories are searched from the package containing the main configuration class (the one annotated with @EnableAutoConfiguration
or @SpringBootApplication
) and down the hierarchy.
The following example shows a typical interface definition for interacting with a Spring Data repository:
public interface CityRepository extends Repository<City, Long> { Mono<City> findByNameAndStateAllIgnoringCase(String name, String state); }
interface CityRepository : Repository<City?, Long?> { fun findByNameAndStateAllIgnoringCase(name: String?, state: String?): Mono<City?>? }
GO TO FULL VERSION