R2DBC = R2D2 + JDBC
(enfin presque…)
Bruno Bonnin
#DevoxxMA
Rejoignez-nous: https://www.kereis.com/nous-rejoindre/
UN SYSTEME REACTIF…
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
REACTIVE
STREAMS
The purpose of Reactive Streams is to provide a standard for
asynchronous stream processing with non-blocking backpressure.
“
”
REACTIVE STREAMS
REACTIVE STREAMS
Des principes
Reactive Manifesto
Des API
Subscriber, Publisher
Des implémentations
Reactor, RxJava, …
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
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> {}
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
REACTIVE API ET BASE DE DONNÉES
Driver Java v2
X DevAPI
(CompletableFuture)
SqlClient
ADBA
JDBC Reactive Extension
Reactive Driver
R2DBC
Reactive Relational
Database Connectivity
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
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
SPRING DATA R2DBC
UN PEU DE DÉPENDANCES POUR
COMMENCER…
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
spring:
r2dbc:
url: r2dbc:postgresql://localhost:15432/robot_db
username: king_of_salsa
password: un_truc_hyper_compliqué_noté_sur_un_postit
…ET UN PEU DE
CONFIGURATION…
DatabaseClient databaseClient =
DatabaseClient.create(connectionFactory);
Flux<Robot> robots = databaseClient
.sql("SELECT * FROM robot WHERE name = :name")
.bind("name", name)
.map(row -> …)
.all();
CLASSE DatabaseClient
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
public interface RobotRepository
extends ReactiveCrudRepository<Robot, Long> {
Flux<Robot> findByName(String name);
@Query("select distinct movie from robot")
Flux<String> getMovies();
}
CLASSE Reactive***Repository
@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);
}
ECO-SYSTEME
ÉCOSYSTÈME - DRIVERS
[Devoxx MA 2023] R2DBC = R2D2 + JDBC (enfin presque...)
ÉCOSYSTÈME - CLIENTS
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
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
PROJET LOOM
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)
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
LOOM VA TUER LA PROGRAMMATION
REACTIVE ?
Peut-être… ou pas
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 :(
MERCI !
Démos: https://github.com/bbonnin/intro-r2dbc
Images: https://duotone.shapefactory.co/
BACKUP SLIDES
AVEC CONTENU
D’UN SYSTÈME SYNCHRONE ET
BLOQUANT…
Thread de traitement Thread bloqué !
Worker
thread
Hyper simplifié :)
Poursuite du traitement
… À 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

Contenu connexe

PPTX
Démystification de Spring une histoire de pattern
PPTX
Développer sereinement avec Node.js
PPTX
Meetup angular rshop
PDF
Play framework - Human Talks Grenoble - 12.02.2013
DOCX
Activity
PPT
Java Database Connectivity
PDF
Introduction à React
PDF
RSocket un protocole réseau pour les Reactive Streams
Démystification de Spring une histoire de pattern
Développer sereinement avec Node.js
Meetup angular rshop
Play framework - Human Talks Grenoble - 12.02.2013
Activity
Java Database Connectivity
Introduction à React
RSocket un protocole réseau pour les Reactive Streams

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

PPTX
Meetup angular rshop
PPT
ACRA - Présentation PAUG Avril 2011
PPT
ASP.NET Futures
PPT
Asp.Net Futures
PDF
react-fr.pdf
PDF
Flex, une techno RIA incontournable pour les futures app web ?
ODP
GWT : under the hood
PPTX
Introduction au Spring microservices Batch.pptx
PPTX
Introduction au Spring Batch pour microservices.pptx
PPTX
Introduction au Spring Batch pour microservices.pptx
PPTX
Introduction au Spring Batch pour microservices.pptx
PPTX
HTML5 en projet
PDF
Introduction à Angularjs
PDF
Cours PHP PDO intégrale afin de mieux appréhender la nouvelle librairie
PDF
2016_js_react.pdf
PDF
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
PPT
Linq et Entity framework
PDF
iTunes Stats
PDF
Support Java Avancé Troisième Partie
PPTX
Tableau de bord Yammer sous SharePoint 2013
Meetup angular rshop
ACRA - Présentation PAUG Avril 2011
ASP.NET Futures
Asp.Net Futures
react-fr.pdf
Flex, une techno RIA incontournable pour les futures app web ?
GWT : under the hood
Introduction au Spring microservices Batch.pptx
Introduction au Spring Batch pour microservices.pptx
Introduction au Spring Batch pour microservices.pptx
Introduction au Spring Batch pour microservices.pptx
HTML5 en projet
Introduction à Angularjs
Cours PHP PDO intégrale afin de mieux appréhender la nouvelle librairie
2016_js_react.pdf
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
Linq et Entity framework
iTunes Stats
Support Java Avancé Troisième Partie
Tableau de bord Yammer sous SharePoint 2013
Publicité

Plus de Bruno Bonnin (18)

PDF
Stream processing avec Apache Pulsar
PDF
Stream processing et SQL
PDF
Stream processing et SQL
PDF
Guide (un tout petit peu) pratique (et totalement subjectif) du stream proces...
PDF
Stream processing et SQL
PDF
Stream processing et SQL
PDF
Jug summer camp 2017 - Vue.js, même un dev java peut en faire !
PDF
A la découverte de vue.js
PDF
Vue.js, même un dev java peut en faire !
PDF
Explorez vos données présentes dans MongoDB avec Apache Zeppelin
PDF
Vue, j’avais pas vu !
PDF
Apache Spark avec NodeJS ? Oui, c'est possible avec EclairJS !
PDF
Big Data Viz (and much more!) with Apache Zeppelin
PDF
Tout ce que le getting started mongodb ne vous dira pas
PDF
Explorez vos données avec apache zeppelin
PDF
Tout ce que le getting started MongoDB ne vous dira pas
PPTX
MUG Nantes - MongoDB et son connecteur pour hadoop
PDF
Breizhcamp 2015 - Comment (ne pas réussir à) modéliser ses data dans elastics...
Stream processing avec Apache Pulsar
Stream processing et SQL
Stream processing et SQL
Guide (un tout petit peu) pratique (et totalement subjectif) du stream proces...
Stream processing et SQL
Stream processing et SQL
Jug summer camp 2017 - Vue.js, même un dev java peut en faire !
A la découverte de vue.js
Vue.js, même un dev java peut en faire !
Explorez vos données présentes dans MongoDB avec Apache Zeppelin
Vue, j’avais pas vu !
Apache Spark avec NodeJS ? Oui, c'est possible avec EclairJS !
Big Data Viz (and much more!) with Apache Zeppelin
Tout ce que le getting started mongodb ne vous dira pas
Explorez vos données avec apache zeppelin
Tout ce que le getting started MongoDB ne vous dira pas
MUG Nantes - MongoDB et son connecteur pour hadoop
Breizhcamp 2015 - Comment (ne pas réussir à) modéliser ses data dans elastics...
Publicité

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

  • 1. R2DBC = R2D2 + JDBC (enfin presque…) Bruno Bonnin #DevoxxMA
  • 4. 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
  • 6. The purpose of Reactive Streams is to provide a standard for asynchronous stream processing with non-blocking backpressure. “ ” REACTIVE STREAMS
  • 7. REACTIVE STREAMS Des principes Reactive Manifesto Des API Subscriber, Publisher Des implémentations Reactor, RxJava, …
  • 8. 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
  • 9. 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> {}
  • 10. 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
  • 11. REACTIVE API ET BASE DE DONNÉES Driver Java v2 X DevAPI (CompletableFuture) SqlClient ADBA JDBC Reactive Extension Reactive Driver
  • 13. 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
  • 14. 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
  • 16. UN PEU DE DÉPENDANCES POUR COMMENCER… <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-r2dbc</artifactId> </dependency>
  • 17. spring: r2dbc: url: r2dbc:postgresql://localhost:15432/robot_db username: king_of_salsa password: un_truc_hyper_compliqué_noté_sur_un_postit …ET UN PEU DE CONFIGURATION…
  • 18. DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); Flux<Robot> robots = databaseClient .sql("SELECT * FROM robot WHERE name = :name") .bind("name", name) .map(row -> …) .all(); CLASSE DatabaseClient
  • 19. 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
  • 20. public interface RobotRepository extends ReactiveCrudRepository<Robot, Long> { Flux<Robot> findByName(String name); @Query("select distinct movie from robot") Flux<String> getMovies(); } CLASSE Reactive***Repository
  • 21. @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); }
  • 26. 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
  • 27. 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
  • 29. 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)
  • 30. 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
  • 31. LOOM VA TUER LA PROGRAMMATION REACTIVE ? Peut-être… ou pas
  • 32. 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 :(
  • 33. MERCI ! Démos: https://github.com/bbonnin/intro-r2dbc Images: https://duotone.shapefactory.co/
  • 35. D’UN SYSTÈME SYNCHRONE ET BLOQUANT… Thread de traitement Thread bloqué ! Worker thread Hyper simplifié :) Poursuite du traitement
  • 36. … À 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