A reactive API for Hibernate ORM, supporting non-blocking database drivers and a reactive style of interaction with the database.
Hibernate Reactive has been tested with:
Support for SQL Server is coming soon.
Integration with Quarkus has been developed and tested but has not yet been released.
Usage is very straightforward for anyone with any prior experience with Hibernate or JPA.
Add the following dependency to your project:
You'll also need to add a dependency for the Vert.x reactive database driver for your database, for example:
io.vertx:vertx-mysql-clientfor MySQL, or
There's an example Gradle build included in the example program.
Use the regular JPA mapping annotations defined in the package
javax.persistence, and/or the Hibernate mapping annotations in
Most mapping annotations are already supported in Hibernate Reactive. The annotations which are not yet supported are listed in Limitations, below.
Hibernate Reactive is configured via the standard JPA
document which must be placed, as usual, in the
The only configuration specific to Hibernate Reactive is the persistence
<provider> element, which must be explicit:
Otherwise, configuration is almost completely transparent. Configure Hibernate exactly as you usually would, noting that most configuration properties related to JDBC or JTA aren't relevant in the context of Hibernate Reactive.
Configuration properties of particular interest include:
javax.persistence.jdbc.url, the JDBC URL of your database,
javax.persistence.jdbc.password, the database credentials, and
hibernate.connection.pool_size, the size of the Vert.x reactive connection pool.
The Vert.x database client has built-in connection pooling and prepared statement caching. During performance tuning, you can further customize the pool and cache via the following properties:
(But for now, just leave these settings alone.)
persistence.xml file is included in the example
Obtain a Hibernate
SessionFactory or JPA
just as you normally would, for example, by calling:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("example");
unwrap() the reactive
Stage.SessionFactory sessionFactory = emf.unwrap(Stage.SessionFactory.class);
Stage.SessionFactory gives access to reactive APIs based on
If you prefer to use the Mutiny-based API,
unwrap() the type
Mutiny.SessionFactory sessionFactory = emf.unwrap(Mutiny.SessionFactory.class);
To obtain a reactive
Session from the
sessionFactory.withSession( session -> ... //do some work );
Alternatively, you can use
openSession(), but you must remember to
the session when you're done.
sessionFactory.openSession() .thenCompose( session -> ... //do some work .whenComplete( ($,e) -> session.close() ) );
Session interface has methods with the same names as methods of the
EntityManager. However, each of these methods returns its result via
CompletionStage (or Mutiny
Uni), for example:
session1.find(Book.class, book.id) .thenAccept( book -> System.out.println(book.title + " is a great book!") )
Methods with no meaningful return value return a reference to the
session2.persist(book) .thenCompose( $ -> session2.flush() ) .whenComplete( ($,e) -> session2.close() )
createQuery() method produces a reactive
Query, allowing HQL / JPQL
queries to be executed asynchronously, always returning their results via a
session3.createQuery("select title from Book order by title desc") .getResultList() .thenAccept(System.out::println)
If you already know Hibernate, and if you already have some experience with reactive programming, there's not much new to learn here: you should immediately feel right at home.
In Hibernate ORM, lazy associations are fetched transparently when the
association is fist accessed within a session. In Hibernate Reactive,
association fetching is an asynchronous process that produces a result
CompletionStage (or Mutiny
Therefore, lazy fetching is an explicit operation named
a static method of
session4.find(Author.class, author.id) .thenCompose( author -> Stage.fetch(author.books) ) .thenAccept( books -> ... )
Of course, this isn't necessary if you fetch the association eagerly.
Similarly, field-level lazy fetching—an advanced feature, which is only supported in conjunction with Hibernate's optional compile-time bytecode enhancer—is also an explicit operation:
session5.find(Book.class, book.id) .thenCompose( book -> session.fetch(book, Book_.isbn) ) .thenAccept( isbn -> ... )
Note that the field to fetch is identified by a JPA metamodel
We don't encourage you to use field-level lazy fetching unless you have very specific requirements.
withTransaction() method performs work within the scope of a database
session.withTransaction( tx -> session.persist(book) )
The session is automatically flushed at the end of the transaction.
For extra convenience, there's a method that opens a session and starts a transaction in one call:
sessionFactory.withTransaction( (session, tx) -> session.persist(book) )
Sequence, table, and
UUID id generation is built in, along with support
for assigned ids.
Custom id generators may be defined by implementing
and declaring the custom implementation using
There is a very simple example program in the
The project is built with Gradle, but you do not need to have Gradle installed on your machine.
To compile this project, navigate to the
To publish Hibernate Reactive to your local Maven repository, run:
To run the tests, you'll need to decide which RDBMS you want to test with, and then get an instance of the test database running on your machine.
By default, the tests will be run against PostgreSQL. To test against
MySQL or DB2, you must explicitly specify
./gradlew test -Pdb=db2
There are three ways to start the test database.
If you have Docker installed, running the tests is really easy. You don't need to create the test databases manually. Just type:
./gradlew test -Pdocker
./gradlew test -Pdocker -Pdb=mysql
./gradlew test -Pdocker -Pdb=db2
The tests will run faster if you reuse the same containers across
multiple test runs. To do this, edit the testcontainers configuration
.testcontainers.properties in your home directory, adding the
testcontainers.reuse.enable=true. (Just create the file if it
doesn't already exist.)
If you already have PostgreSQL installed on your machine, you'll just need to create the test database. From the command line, type the following commands:
psql create database hreact; create user hreact with password 'hreact'; grant all privileges on database hreact to hreact;
./gradlew test from the
If you have MySQL installed, you can create the test database using the following commands:
mysql -uroot create database hreact; create user hreact identified by 'hreact'; grant all on hreact.* to hreact;
./gradlew test -Pdb=mysql from the
To run the tests, type
./gradlew test from the
We're working hard to support the full feature set of Hibernate ORM. At present a few limitations remain.
At this time, Hibernate Reactive does not support the following mapping features:
@OneToMany(mappedBy=...) together with
There is no block optimization for the
TABLE id generators.
Currently there is no support for batched inserts and updates. The setting
hibernate.jdbc.batch_size is ignored.
delete queries which affect multiple tables (due to the
JOINED inheritance mapping) are not working.
The query cache is not yet supported.
Note that you should not use Hibernate Reactive with a second-level cache implementation which performs blocking IO, for example passivation to the filesystem or distributed replication.
You might run into some limitations of the Vert.x DB2 client when using Hibernate Reactive with DB2.