Reaktive Daten mit R2DBC
Mit einer Datenbank sprechen, ohne zu blockieren, damit die gesamte Anfragepipeline durchgängig reaktiv bleibt.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
A reactive web layer is only half the story. If your controller returns a Flux but then
calls blocking JPA, a database thread is tied up per query and the non-blocking benefit
evaporates. To stay reactive from HTTP request to database and back, you need a non-blocking
database driver: R2DBC (Reactive Relational Database Connectivity).
Reactive repositories
Spring Data R2DBC mirrors the Spring Data JPA model you know, but every method returns a publisher:
interface BookRepository extends ReactiveCrudRepository<Book, Long> {
Mono<Book> findByIsbn(String isbn); // one, asynchronously
Flux<Book> findByAuthor(String author); // many, streamed
}save, findById, findAll all return Mono/Flux instead of blocking and returning a
value directly. The database call never parks a thread; results flow back as they're ready.
Blocking JDBC is fetching water in a bucket: you walk to the well, wait for it to fill, and carry it back - standing idle the whole time. R2DBC is a conveyor belt from the well: you start it and walk away, and water arrives continuously without anyone standing and waiting. The thread isn't held hostage by the round trip.
The catch: no JPA
R2DBC is not JPA/Hibernate. There's no entity manager, no lazy loading, no automatic
relationship graphs, no @OneToMany navigation. You get a lighter, more explicit mapping and
you handle relationships yourself. That's a real cost - you give up a lot of ORM convenience
to gain non-blocking access.
Only go reactive if the whole chain does
The rule from the last lesson applies at the data layer too: mixing blocking JPA into a reactive pipeline blocks the event loop. If you commit to WebFlux, commit to R2DBC (or another reactive driver) as well - and accept trading Hibernate's conveniences for non-blocking I/O. If you don't need that, stay on JPA.
A team builds a WebFlux endpoint that returns Flux<Book> but fetches data with a normal
JPA BookRepository. Under high load it performs no better than the blocking version - and
sometimes worse. Explain why, and what single change fixes it (and what they give up).
Why does a reactive (WebFlux) pipeline need R2DBC rather than JPA/JDBC?
Key takeaways
- To be reactive end to end, the data layer must be non-blocking too - that's R2DBC.
- Spring Data R2DBC mirrors Spring Data JPA but repository methods return Mono/Flux.
- R2DBC is not JPA: no entity manager, lazy loading, or automatic relationship graphs - you map more explicitly.
- Mixing blocking JPA into a reactive pipeline blocks the event loop and can perform worse than plain MVC.
- Adopt R2DBC only when you've committed to reactive; otherwise JPA's conveniences win.