For the first time in years, we have a new toplevel subproject here at hibernate.org!
Reactive programming and relational databases
Reactive programming lets us take advantage of non-blocking IO to reduce resource usage in our programs. For a long time, non-blocking IO was something that just wasn’t an option for programs which interact with relational databases, since data access APIs like JDBC and ODBC were designed around a fundamentally synchronous, blocking paradigm.
That’s changed quite recently, with initiatives like the Vert.x client APIs for PostgreSQL, MySQL, Db2, and SQL Server, along with other similar projects. Thus, it’s now possible for a Java program to interact with a relational database in a completely asynchronous, non-blocking fashion.
Furthermore, APIs like Mutiny simplify reactive programming using streams instead of nested callbacks, alleviating at least some of the pain of asynchronous programming in Java.
But of course back in 2006, when we designed the Java Persistence API to simplify ORM in Java and unify the ORM implementations that existed at the time, "reactive programming" just wasn’t on anyone’s radar. So JPA is fundamentally blocking in nature. "Reactive ORM" is something that simply hasn’t existed.
A reactive API for ORM
So today we’re introducing the community to Hibernate Reactive, a reactive API for Hibernate ORM, which supports non-blocking database clients and reactive programming as a paradigm for interacting with the relational database.
Hibernate Reactive reuses most of the implementation of Hibernate ORM, but replaces
the code which interacts with JDBC with a new layer designed around reactive streams,
and exposes a new reactive Session
API to the programmer.
In fact, there’s two reactive Session
APIs, one for programs using Mutiny,
and one for programs using Java’s CompletionStage
.
// Mutiny-based API
factory.withTransaction(
// retrieve a Book
(session, tx) -> session.find(Book.class, bookId)
// delete the Book
.chain(book -> session.remove(book))
)
Naturally we kept as much as possible from JPA and Hibernate ORM, including the OR mapping annotations, and the naming and semantics of the basic persistence operations, and options for tuning performance. Even most of the configuration properties will be familiar to users of JPA and Hibernate.
If you’ve used Hibernate before, and if you’ve also done some programming with reactive streams, you should be immediately right at home with Hibernate Reactive. If you’ve never used Hibernate, or if you’ve never done reactive programming, well, here’s an opportunity to learn something new, and we’re here to help!
Whichever situation applies to you, the best starting point is our Introduction to Hibernate Reactive.
The bigger picture
Hibernate Reactive is only really useful in the context of a stack of end-to-end reactive technologies. So of course we’re making sure it works great with Vert.x, and that it’s straightforward to integrate into other platforms.
But the exciting news here is that we’re also integrating it with a new reactive API for Quarkus that we’ll announce very soon. Our goal is to provide the most comfortable and familiar way for Java developers to transition to a reactive programming model.
We’ll have more to say about reactive data access in Quarkus in a future post.
We’re also working to expand this list of supported databases. Currently, only PostgreSQL, MySQL, and Db2 are supported, but we hope to introduce support for SQL Server soon.
Performance considerations
While the immediate goal of this project was simply to let you use ORM with a non-blocking database client library, and from within the reactive programming model, it’s clear that we would hope to obtain some performance benefits compared to using ORM together with blocking JDBC drivers. On the other hand, one can’t reasonably expect Hibernate Reactive to be faster than regular Hibernate ORM in all or even most situations.
In particular, if you test data access performance on your laptop with a program accessing a local database with a teensy amount of data that fits completely in the database’s cache, then there’s no reason at all for you to expect to see a performance improvement with Hibernate Reactive. We don’t magically make it faster to read bytes from memory!
But even in many much more realistic situations, reactive code isn’t automatically faster than regular code using blocking IO. To measure an effect, you would need a situation where many server threads would block waiting for a response from a remote database server.
In our testing, we have seen evidence that the performance of code using Hibernate Reactive degrades more gracefully than code using regular Hibernate ORM in a test environment designed to emulate this situation, but I must add the strong caveat that these are preliminary results, which won’t necessarily generalize to all systems.
So, as usual, I strongly urge you to do your own performance testing, of your own program, in your own production runtime environment, with your own typical workloads.
On the other hand, we have not even begun to optimize the performance of Hibernate Reactive, so the initial performance tests were really rather encouraging.