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

R2DBC = R2D2 + JDBC (enfin presque...) [Devoxx MA 2023]

R2DBC = R2D2 + JDBC (enfin presque...) [Devoxx MA 2023]

Présentation sur R2DBC faite à Devoxx Morocco 2013

Bruno Bonnin

October 13, 2023
Tweet

More Decks by Bruno Bonnin

Other Decks in Programming

Transcript

  1. UN PEU D’HISTOIRE… Reactive Manifesto 2009 2011 2013 Reactive Streams

    2015 2018 2017 ReactiveX Spring Webflux JDK 9 RxJava Project Reactor (v2 avec Reactive Streams) Driver Java v2 2019 Spring Data R2DBC R2DBC 2022 R2DBC v1.0
  2. The purpose of Reactive Streams is to provide a standard

    for asynchronous stream processing with non-blocking backpressure. “ ” REACTIVE STREAMS
  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) La source des données Le consommateur des données
  4. IMPLÉMENTATION AVEC PROJET 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("😭" + exc)) // Error consumer .doOnComplete(() -> System.out.println("🎉")) // Complete consumer .subscribe(); // Publisher de 0 à n éléments public abstract class Flux<T> implements CorePublisher<T> {}
  5. Base de données Application 1. subscribe 3. request(n) / cancel

    2. onSubscribe (subscription) 4. onNext(“R2D2”) 5. onComplete / onError ET SI C’ETAIT UNE REQUETE… Subscription 4. onNext(“C3PO”) 4. onNext(“BB-8”) SELECT name FROM robot
  6. REACTIVE API ET BASE DE DONNÉES Driver Java v2 X

    DevAPI (CompletableFuture) SqlClient ADBA JDBC Reactive Extension Reactive Driver
  7. 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
  8. 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
  9. DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); Flux<Robot> robots = databaseClient .sql("SELECT *

    FROM robot WHERE name = :name") .bind("name", name) .map(row -> …) .all(); CLASSE DatabaseClient
  10. 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); CLASSE R2dbcEntityTemplate
  11. public interface RobotRepository extends ReactiveCrudRepository<Robot, Long> { Flux<Robot> findByName(String name);

    @Query("select distinct movie from robot") Flux<String> getMovies(); } CLASSE Reactive***Repository
  12. @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); }
  13. R2DBC PROXY Librairie fournissant des callbacks permettant d’accéder à l’exécution

    des requêtes, pour: - logging, - métriques, - traçage distribué, - … R2DBC Driver R2DBC Proxy Application
  14. R2DBC ET MULTI-TENANCY Comment gérer plusieurs connexions selon un contexte

    d’exécution ? - AbstractR2dbcRouting : configuration des différentes connexions - AbstractRoutingConnectionFactory : fournit la clé de sélection de la connexion
  15. JAVA ET LES THREADS 1996 Java 1 Thread, Runnable 2004

    Java 5 java.util.concurrent Callable, Future Lock, Semaphore 2011 Java 7 ForkJoinTask 2014 Java 8 CompletableFuture CompletionStage 2023 Java 21 Virtual threads (preview depuis v19)
  16. LOOM VA TUER LA PROGRAMMATION REACTIVE ? Movie getRobotFirstMovie(String robotName)

    { Robot robot = repository.findRobotByName(robotName); Movie movie = repository.findMovieById(robot.firstMovie); return movie; } Movie getRobotFirstMovie(String robotName) { CompletableFuture<Robot> robotFuture = CompletableFuture .supplyAsync(() -> repository.findRobotByName(robotName)); CompletableFuture<Movie> movieFuture = robotFuture .thenApplyAsync(robot -> repository.findMovieById(robot.firstMovie)); return movieFuture.get(); } Mono<Movie> getFirstMovie(String robotName) { return repository.findRobotByName(robotName) .flatMap(robot -> repository.findMovieById(robot.firstMovie)) …. // Pleins de traitement: log, zip, map, … .onErrorReturn(new Movie("Star Wars IV")); } ? @RunOnVirtualThread
  17. 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 :(
  18. D’UN SYSTÈME SYNCHRONE ET BLOQUANT… Thread de traitement Thread bloqué

    ! Worker thread Hyper simplifié :) Poursuite du traitement
  19. … À UN SYSTÈME ASYNCHRONE ET NON BLOQUANT ! Traitement

    d’une requête Événement (tâche à réaliser avec callback) Invocation callback Event loop Traitement tâche Modèle “Event Loop” Événement (résultat traitement tâche) Worker threads