Reactive Relational Database Connectivity

Reactive Relational Database Connectivity (R2DBC) (https://github.com/r2dbc) is an initiative to explore what an entirely reactive database API may look like. The Spring Data team leads the R2DBC initiative and uses it to probe and verify ideas in the context of reactive data access within reactive applications. R2DBC was publicly announced at the Spring OnePlatform 2018 conference. R2DBC has the aim of defining a reactive database access API with backpressure support. The Spring Data team gained some excellent experience with reactive NoSQL persistence, so they decided to propose their vision of what a genuinely reactive language-level data access API may look like. Also, R2DBC may become an underlying API for the relational reactive repositories in Spring Data. At the time of writing, R2DBC is still experimental, and it is unclear whether or when it may become a production-ready software.

The R2DBC project consists of the following parts:

  • R2DBC Service Provider Interface (SPI) defines the minimalistic API for driver implementations. The API is concise in order to drastically trim down the API that driver implementors had to conform to. The SPI is not intended for direct use from the application code. Instead, a dedicated client library is required for that purpose.
  • R2DBC Client offers a human-friendly API and helper classes that translate user requests to the SPI level. This separate level of abstraction adds some comfort when using R2DBC directly. The authors highlight that R2DBC Client does for R2DBC SPI the same things as the Jdbi library does for JDBC. However, anyone is free to use SPI directly or implement their own client library over R2DBC SPI.
  • R2DBC PostgreSQL Implementation provides a R2DBC driver for PostgreSQL. It uses the Netty framework for asynchronous communication via the PostgreSQL wire protocol. Backpressure may be achieved either by TCP Flow Control or by a PostgreSQL feature called portal, which is effectively a cursor into a query. The portal translates perfectly to Reactive Streams. It is important to note that not all relational databases have the wire protocol features required for a proper backpressure propagation. However, at least TCP Flow Control is available in all cases.

R2DBC Client allows working with the PostgreSQL database as follows:

PostgresqlConnectionFactory pgConnectionFactory =                  // (1)
    PostgresqlConnectionConfiguration.builder()
       .host("<host>")
       .database("<database>")
       .username("<username>")
       .password("<password>")
       .build();

R2dbc r2dbc = new R2dbc(pgConnectionFactory);                      // (2)

r2dbc.inTransaction(handle ->                                      // (3)
   handle
      .execute("insert into book (id, title, publishing_year) " +  // (3.1)
               "values ($1, $2, $3)",
               20, "The Sands of Mars", 1951)
      .doOnNext(n -> log.info("{} rows inserted", n))              // (3.2)
).thenMany(r2dbc.inTransaction(handle ->                           // (4)
      handle.select("SELECT title FROM book")                      // (4.1)
         .mapResult(result ->                                      // (4.2)
            result.map((row, rowMetadata) ->                       // (4.3)
               row.get("title", String.class)))))                  // (4.4)
   .subscribe(elem -> log.info(" - Title: {}", elem));             // (5)

Let's describe the preceding code:

  1. First of all, we have to configure a connection factory represented by the PostgresqlConnectionFactory class. The configuration is trivial.
  2. We have to create an instance of the R2dbc class, which provides the reactive API.
  3. R2dbc allows us to create a transaction by applying the inTransaction method. A handle wraps an instance of the reactive connection and provides additional convenience APIs. Here, we may execute an SQL statement, for example, insert a new row. The execute method receives an SQL query and its parameters, if any (3.1). In turn, the execute method returns the number of affected rows. In the preceding code, we log the number of updated rows (3.2).
  4. After inserting a row, we start another transaction to select all book titles (4.1). When the result arrives, we map individual rows (4.2) by applying the map function (4.3), which know about the row structure. In our case, we retrieve the title of the String type (4.4). The mapResult method returns the Flux<String> type.
  5. We log all onNext signals reactively. Each signal holds a book title, including the one inserted at step (3).

As we can see, R2DBC Client provides a fluent API with the reactive style. This API feels very natural in the code base of reactive applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.62.122