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

R2DBC = R2D2 + JDBC (enfin presque...)

R2DBC = R2D2 + JDBC (enfin presque...)

Présentation de R2DBC faite à Devoxx France en avril 2022

Bruno Bonnin

April 20, 2022
Tweet

More Decks by Bruno Bonnin

Other Decks in Programming

Transcript

  1. Reactive API et base de données ? Driver Java v2

    X DevAPI (CompletableFuture) SqlClient ADBA JDBC Reactive Extension Reactive Driver
  2. Définit une interface standard de programmation réactive basée sur les

    Reactive Streams, destinée aux interactions avec les bases de données relationnelles. Reactive Streams R2DBC SPI R2DBC Driver X
  3. Publisher Subscriber 1. subscribe 3. request(n) / cancel 2. onSubscribe

    (subscription) 4. onNext(data 1) 5. onComplete / onError Reactive Streams API Subscription 4. onNext(data …) 4. onNext(data n)
  4. Implémentation avec Project Reactor // Publisher de 0 à 1

    élément public abstract class Mono<T> implements CorePublisher<T> {} Flux.just("Hello", "How", "Are", "You?") .doOnNext(System.out::println) // Data consumer .doOnError(exc -> System.err.println("Sniff… " + exc)) // Error consumer .doOnComplete(() -> System.out.println("Fini !!")) // Complete consumer .subscribe(); // Publisher de 0 à n éléments public abstract class Flux<T> implements CorePublisher<T> {}
  5. ConnectionFactory connectionFactory = ConnectionFactories.get("r2dbc:h2:mem:///robot_db"); R2DBC + Reactive Streams + Project

    Reactor = ❤ Publisher<? extends Connection> connectionPublisher = connectionFactory.create(); Mono.from(connectionPublisher) .flatMapMany(connection -> connection .createStatement("SELECT * FROM robot WHERE name = $1") .bind("$1", "R2-D2") .execute()) .flatMap(result -> result.map((row, metadata) -> /* … */)) .doOnNext(data -> …) // Traitement donnée .doOnError(exc -> …) // Traitement erreur .doOnComplete(() -> …) // Traitement fin .subscribe(); // Lancement du traitement
  6. DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); Flux<Robot> robots = databaseClient .sql("SELECT *

    FROM robot WHERE name = :name") .bind("name", name) .map(row -> …) .all(); DatabaseClient
  7. Flux<Robot> robots = r2dbcEntityTemplate .select(Robot.class) .from("robot") .matching(query(where("name").is(name))) .all(); Flux<Robot> robots

    = r2dbcEntityTemplate .select( query(where("name").is(name)), Robot.class); R2dbcEntityTemplate
  8. public interface RobotRepository extends ReactiveCrudRepository<Robot, Long> { Flux<Robot> findByName(String name);

    @Query("select distinct movie from robot") Flux<String> getMovies(); } Reactive***Repository
  9. @Transactional public Mono<Void> create(Robot robot, Movie movie) { return robotRepository.save(robot)

    .then(movieRepository.save(movie)) .then(); } Et avec un zeste de transaction ! public Mono<Void> create(Robot robot, Movie movie) { TransactionalOperator rxtx = TransactionalOperator.create(reactiveTxManager ); return robotRepository.save(robot) .then(movieRepository.save(movie)) .then() .as(rxtx::transactional); }
  10. R2DBC Proxy Librairie fournissant des callbacks permettant d’accéder à l’exécution

    des requêtes, pour: - logging, - métriques, - traçage distribué, - … R2DBC Proxy R2DBC Driver Application
  11. En résumé… Qu’a-t-on vu ? - Initiative plus qu’intéressante pour

    standardiser l’accès aux bases de données relationnelles en mode réactif - Il y a aussi des transactions, du batch, des entity callbacks, de l’observability, … - Support de la communauté (clients, drivers, …) - On peut faire du R2DBC sans aucun autre framework, mais ça va être un peu roots :) Mais il reste du boulot ! - Des frameworks en cours de mises à jour (Liquibase, …) - Spring : pas de support des relations dans les entités :(