Upgrade to Pro — share decks privately, control downloads, hide ads and more …

R2DBC JEEConf 2019 by Igor Lozynskyi

R2DBC JEEConf 2019 by Igor Lozynskyi

R2DBC as a reactive API for data access in SQL databases.
Presented at JEEConf 2019 by Igor Lozynskyi.

Igor Lozynskyi

April 26, 2019
Tweet

More Decks by Igor Lozynskyi

Other Decks in Programming

Transcript

  1. For whom this talk: / Want to build reactive apps?

    / Want to have reactive database access? / Want lo learn about R2DBC? / I assume, you know what Reactive is
  2. Why Reactive? / New frontier for high-efficiency apps / Fundamentally

    non-blocking / Paired with asynchronous behaviors / Pull-push back pressure
  3. Why Reactive? / New frontier for high-efficiency apps / Fundamentally

    non-blocking / Paired with asynchronous behaviors / Pull-push back pressure
  4. ADBA / New async API for relational data access in

    Java / Implemented with CompletableFuture / Uses Java 9’s Flow API
  5. Criticism / Does not imply back pressure / Has only

    ADBA-over-JDBC implementation / Slow development / Authors have neglected Reactive approach for a long time / No clear timeline
  6. R2DBC Design principles / Based on Reactive Streams Types and

    Patterns / Be completely non-blocking, up to the DB / Utilize wire-protocol for non-blocking implementations / Divide Client API and Driver SPI / Shrink Driver SPI
  7. JDBC API / JDBC has the same API for: /

    Driver authors / Human users / Inhuman users like JPA, Jdbi, jOOQ, etc. / No-one likes using JDBC API
  8. R2DBC SPI - Connection / Batch createBatch() / Statement createStatement(String

    sql) / Publisher<Void> beginTransaction() / Publisher<Void> commitTransaction() / Publisher<Void> rollbackTransaction() / Publisher<Void> rollbackTransactionToSavepoint(String name) / Publisher<Void> setTransactionIsolationLevel(IsolationLevel level) / Publisher<Void> createSavepoint(String name) / Publisher<Void> releaseSavepoint(String name) / Publisher<Void> close()
  9. R2DBC SPI - Statement / Statement add() / Statement bind(Object

    identifier, Object value) / Statement bindNull(Object identifier, Class<?> type) / Publisher<? extends Result> execute() / Statement returnGeneratedValues(String... columns)
  10. R2DBC SPI - Result / Publisher<Integer> getRowsUpdated() / <T> Publisher<T>

    map(BiFunction<Row, RowMetadata, ? extends T> f)
  11. SPI: Simple select connectionFactory .create() .flatMapMany(conn -> conn.createStatement("SELECT currency, price

    FROM trades") .execute() .flatMap(result -> result .map((row, metadata) -> row.get("currency"))))
  12. SPI: Batch insert connectionFactory .create() .flatMapMany(conn -> conn.createStatement( “INSERT INTO

    trades (currency, market, price) “ + "VALUES (?, ?, ?)") .bind(0, "EUR").bind(1, "TD").bind(2, 7.0).add() .bind(0, "UAH").bind(1, "TX").bind(2, 6.0).add() .execute())
  13. SPI: Transactions connectionFactory .create() .flatMapMany(conn -> conn.beginTransaction() .thenMany(conn.createStatement( "INSERT INTO

    trades (currency, market, price) " + "VALUES (?, ?, ?)") .bind(0, "UAH").bind(1, "TX").bind(2, "B") .execute()) .delayUntil(p -> conn.commitTransaction()) .onErrorResume(t -> conn .rollbackTransaction() .then(Mono.error(t)))) try-with-resources
  14. R2DBC Client r2dbcClient .withHandle(handle -> handle.createUpdate( "INSERT INTO trades (currency,

    market, price) " + "VALUES ($1, $2, $3)") .bind("$1", "UAH").bind("$2", "TX").bind("$3", 3.4) .execute())
  15. R2DBC Client: Transactions r2dbcClient .inTransaction(handle -> handle.createUpdate( "INSERT INTO trades

    (currency, market, price) " + "VALUES ($1, $2, $3)") .bind("$1", "UAH").bind("$2", "TX").bind("$3", 3.4) .execute())
  16. SPI: Transactions connectionFactory .create() .flatMapMany(conn -> conn.beginTransaction() .thenMany(conn.createStatement( "INSERT INTO

    trades (currency, market, price) " + "VALUES (?, ?, ?)") .bind(0, "UAH").bind(1, "TX").bind(2, "B") .execute()) .delayUntil(p -> conn.commitTransaction()) .onErrorResume(t -> conn .rollbackTransaction() .then(Mono.error(t))))
  17. Spring Data Repository public interface UsSalesR2dbcRepository extends R2dbcRepository<UsSalesDataDto, String> {

    @Query("select * from us_sales_by_districts") Flux<UsSalesDataDto> findAll(); @Query("select * from us_sales_by_districts, where code=:code") Mono<UsSalesDataDto> findById(@Param("code") String code); }
  18. public interface UsSalesR2dbcRepository extends R2dbcRepository<UsSalesDataDto, String> { @Query("select * from

    us_sales_by_districts") Flux<UsSalesDataDto> findAll(); @Query("select * from us_sales_by_districts, where code=:code") Mono<UsSalesDataDto> findById(@Param("code") String code); } Spring Data R2DBC
  19. Longer Queries / DBs rushing to deliver data / Back

    pressure may delay data delivery
  20. Longer Transactions / Back pressure may cause more contention /

    JDBC faster then R2DBC / R2DBC may impact DB internals
  21. Wire-protocol / Should allow data streaming / Should allow back

    pressure / Cancellation / Implement Reactive Streams semantics / Multiplexing? / RSocket?
  22. R2DBC Pros / New and shiny / Brings reactive to

    DB access / More active community than ADBA’s / Easy to implement drivers (compared to JDBC)
  23. R2DBC Cons / Not mature enough (current: 1.0.0.M7) / May

    be beaten by ADBA / No JPA (Hibernate/EclipseLink) / Reactive approach may not fit SQL at all
  24. Summary / ADBA vs R2DBC battle is still going on

    / May soon have reactive DB access / Spring Data drives R2DBC / Not for production yet! / Don’t afraid to try R2DBC!