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

Deep Dive into Reactive Relational Database Acc...

Deep Dive into Reactive Relational Database Access (Devoxx Ukraine 2019)

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

Why reactive, why R2DBC?
How to build PrestoDB R2DBC driver.

Igor Lozynskyi

November 01, 2019
Tweet

More Decks by Igor Lozynskyi

Other Decks in Programming

Transcript

  1. Agenda / Why reactive DB access? / Look at R2DBC

    / Build a toy R2DBC driver / I assume, you know what Reactive is
  2. Reactive Programming / Nonblocking / Usually asynchronous / Declarative /

    Processing streams / Resilient / Back pressure / Reactive Streams Standart / High-efficiency
  3. JDBC / Nonblocking / Usually asynchronous / Declarative / Processing

    streams / Resilient / Back pressure / Reactive Streams Standart / Blocks Threads JDK 1.1 1997 year
  4. R2DBC Design principles / Based on Reactive Streams Types and

    Patterns / Completely non-blocking, up to the DB / Utilize wire-protocol for non-blocking implementations / Divide Client API and Driver SPI / Shrink Driver SPI
  5. R2DBC SPI / ConnectionFactory / Connection / Statement / Result

    / RowMetadata / Row image credits: Jonathan Bregler
  6. 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()
  7. 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)
  8. R2DBC SPI - Result / Publisher<Integer> getRowsUpdated() / <T> Publisher<T>

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

    FROM trades") .execute() .flatMap(result -> result .map((row, metadata) -> row.get("currency"))))
  10. 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())
  11. 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
  12. R2DBC Client R2dbc r2dbcClient = new R2dbc(connectionFactory); 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())
  13. 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())
  14. Spring Boot Starter for R2DBC / Driver discovery by URL

    (r2dbc:mysql://…) / ConnectionFactory / TransactionManager / Actuator integration / Embedded H2 / schema.sql and data.sql / @DataR2dbcTest
  15. 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
  16. Spring Data Repository & Transactions? @Component class TransactionalService { private

    CustomerRepository repository; @Transactional public Mono<Customer> save(Customer customer) { return repository.save(customer).map(it -> { if (it.firstname.equals("Dave")) { throw new IllegalStateException(); } else { return it; } }); } }
  17. Caveats / Requires Project Reactor (Context) / May not work

    with RxJava / Some Rx operators may cancel subscription / Flux.take(10) / Flux.next()
  18. JPA? / No Hibernate / No EclipseLink / No JPA

    so far? / But: Hibernate Rx
  19. Longer Queries / DBs rushing to deliver data / Back

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

    JDBC may be faster than R2DBC / R2DBC may impact DB internals
  21. Wire-protocol & DB design requirements / Should allow data streaming

    / Should allow back pressure / Support query cancellation / Conform to Reactive Streams semantics / Connection multiplexing? / RSocket?
  22. R2DBC Roadmap / 0.8.0 GA in 2019 / 0.9.0: /

    Extended transaction API / EventProvider / Stored Procedures / More R2DBC support in DB-related libraries
  23. What we need? / Java / R2DBC SPI / Project

    Reactor / Java 11 HTTP client (or reactor-netty) / JSON parsing libs / Presto instance
  24. R2DBC Pros / New and shiny / Brings reactive to

    DB access / Active community, huge momentum / Easy to implement drivers
  25. R2DBC Cons / Still not GA (current: 0.8 RC2) /

    No JPA (Hibernate/EclipseLink) / Reactive approach may not fit SQL / Reactive programming is under a thread
  26. Fibers/Coroutines Cons / Light-weight threads / C#, JS has async/await

    / Go, Kotlin has green threads / Write blocking, synchronous code / Don’t use FP, write imperative code / Use JDBC/JPA
  27. / Nonblocking / Usually asynchronous / Declarative / Processing streams

    / Resilient / Back pressure / Reactive Streams Standart Reactive vs Fibers/Coroutines Kotlin Coroutine’s Flow Java / JS / C++ / C# … May be simulated with channels No external libraries
  28. Summary / Will have reactive DB access, soon / Spring

    Data drives R2DBC / It is time to try R2DBC! / Reactive vs Fibers: friends or foes?