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:

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"
There is no need to specify a class name for the driver because Spring Boot obtains the driver through discovery of the R2DBC connection factory.
At a minimum, a URL must be provided. The information specified in the URL takes precedence over individual properties, that is, 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:

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)
        }
    }
}

The following examples show how to set some PostgreSQL connection parameters:

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)
        }
    }
}

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:

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 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:

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?>?
}