Using Hibernate Reactive
Hibernate Reactive is a reactive API for Hibernate ORM, supporting non-blocking database drivers and a reactive style of interaction with the database.
Hibernate Reactive is not a replacement for Hibernate ORM or the future of Hibernate ORM. It is a different stack tailored for reactive use cases where you need high-concurrency. Also, using Quarkus REST (formerly RESTEasy Reactive), our default REST layer, does not require the use of Hibernate Reactive. It is perfectly valid to use Quarkus REST with Hibernate ORM, and if you do not need high-concurrency, or are not accustomed to the reactive paradigm, it is recommended to use Hibernate ORM. |
Hibernate Reactive works with the same annotations and most of the configuration described in the Hibernate ORM guide. This guide will only focus on what’s specific for Hibernate Reactive. |
This technology is considered preview. In preview, backward compatibility and presence in the ecosystem is not guaranteed. Specific improvements might require changing configuration or APIs, and plans to become stable are under way. Feedback is welcome on our mailing list or as issues in our GitHub issue tracker. For a full list of possible statuses, check our FAQ entry. |
Solution
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git
, or download an archive.
The solution is located in the hibernate-reactive-quickstart
directory.
Setting up and configuring Hibernate Reactive
When using Hibernate Reactive in Quarkus, you need to:
-
add your configuration settings in
application.properties
-
annotate your entities with
@Entity
and any other mapping annotations as usual
Other configuration needs have been automated: Quarkus will make some opinionated choices and educated guesses.
Add the following dependencies to your project:
-
the Hibernate Reactive extension:
io.quarkus:quarkus-hibernate-reactive
-
the Reactive SQL client extension for the database of your choice; the following options are available:
-
quarkus-reactive-pg-client
: the client for PostgreSQL or CockroachDB -
quarkus-reactive-mysql-client
: the client MySQL or MariaDB -
quarkus-reactive-mssql-client
: the client for Microsoft SQL Server -
quarkus-reactive-db2-client
: the client for IBM Db2 -
quarkus-reactive-oracle-client
: the client for Oracle
-
For instance:
<!-- Hibernate Reactive dependency -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive</artifactId>
</dependency>
<!-- Reactive SQL client for PostgreSQL -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
// Hibernate Reactive dependency
implementation("io.quarkus:quarkus-hibernate-reactive")
Reactive SQL client for PostgreSQL
implementation("io.quarkus:quarkus-reactive-pg-client")
Annotate your persistent objects with @Entity
,
then add the relevant configuration properties in application.properties
:
application.properties
# datasource configuration
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = quarkus_test
quarkus.datasource.password = quarkus_test
quarkus.datasource.reactive.url = vertx-reactive:postgresql://localhost/quarkus_test (1)
# drop and create the database at startup (use `update` to only update the schema)
quarkus.hibernate-orm.database.generation=drop-and-create
1 | The only different property from a Hibernate ORM configuration |
Note that these configuration properties are not the same ones as in your typical Hibernate Reactive configuration file. They will often map to Hibernate Reactive configuration properties but could have different names and don’t necessarily map 1:1 to each other.
Also, Quarkus will set many Hibernate Reactive configuration settings automatically, and will often use more modern defaults.
Configuring Hibernate Reactive using the standard persistence.xml configuration file is not supported.
|
See section Hibernate Reactive configuration properties for the list of properties you can set in application.properties
.
A Mutiny.SessionFactory
will be created based on the Quarkus datasource
configuration as long as the Hibernate Reactive extension is listed among your project dependencies.
The dialect will be selected based on the Reactive SQL client - unless you set one explicitly.
You can then happily inject your Mutiny.SessionFactory
:
@ApplicationScoped
public class SantaClausService {
@Inject
Mutiny.SessionFactory sf; (1)
public Uni<Void> createGift(String giftDescription) {
Gift gift = new Gift();
gift.setName(giftDescription);
return sf.withTransaction(session -> session.persist(gift)) (2)
}
}
1 | Inject your session factory and have fun |
2 | .withTransaction() will automatically flush at commit |
Make sure to wrap methods modifying your database (e.g. session.persist(entity) ) within a transaction.
|
@Entity
public class Gift {
private Long id;
private String name;
@Id
@SequenceGenerator(name = "giftSeq", sequenceName = "gift_id_seq", allocationSize = 1, initialValue = 1)
@GeneratedValue(generator = "giftSeq")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
To load SQL statements when Hibernate Reactive starts, add an import.sql
file in your src/main/resources/
directory.
This script can contain any SQL DML statements.
Make sure to terminate each statement with a semicolon.
This is useful to have a data set ready for your tests or demos.
Hibernate Reactive configuration properties
There are various optional properties useful to refine your session factory or guide Quarkus' guesses.
When no properties are set, Quarkus can typically infer everything it needs to set up Hibernate Reactive and will have it use the default datasource.
The configuration properties listed here allow you to override such defaults, and customize and tune various aspects.
Hibernate Reactive uses the same properties you would use for Hibernate ORM. You will notice that some properties
contain jdbc
in the name but there is no JDBC in Hibernate Reactive, these are simply legacy property names.
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Configuration property |
Type |
Default |
||
---|---|---|---|---|
Whether Hibernate ORM is enabled during the build. If Hibernate ORM is disabled during the build, all processing related to Hibernate ORM will be skipped,
but it will not be possible to activate Hibernate ORM at runtime:
Environment variable: Show more |
boolean |
|
||
If Environment variable: Show more |
boolean |
|
||
Whether statistics collection is enabled. If 'metrics.enabled' is true, then the default here is considered true, otherwise the default is false. Environment variable: Show more |
boolean |
|||
Whether session metrics should be appended into the server log for each Hibernate session. This only has effect if statistics are enabled ( Environment variable: Show more |
boolean |
|||
Whether metrics are published if a metrics extension is enabled. Environment variable: Show more |
boolean |
|
||
The name of the datasource which this persistence unit uses. If undefined, it will use the default datasource. Environment variable: Show more |
string |
|||
The packages in which the entities affected to this persistence unit are located. Environment variable: Show more |
list of string |
|||
Paths to files containing the SQL statements to execute when Hibernate ORM starts. The files are retrieved from the classpath resources,
so they must be located in the resources directory (e.g. The default value for this setting differs depending on the Quarkus launch mode:
If you need different SQL statements between dev mode, test ( application.properties
Environment variable: Show more |
list of string |
|
||
Pluggable strategy contract for applying physical naming rules for database object names. Class name of the Hibernate PhysicalNamingStrategy implementation Environment variable: Show more |
string |
|||
Pluggable strategy for applying implicit naming rules when an explicit name is not given. Class name of the Hibernate ImplicitNamingStrategy implementation Environment variable: Show more |
string |
|||
Class name of a custom
Environment variable: Show more |
string |
|||
XML files to configure the entity mapping, e.g. Defaults to Environment variable: Show more |
list of string |
|
||
Identifiers can be quoted using one of the available strategies. Set to Environment variable: Show more |
|
|
||
The default in Quarkus is for 2nd level caching to be enabled, and a good implementation is already integrated for you. Just cherry-pick which entities should be using the cache. Set this to false to disable all 2nd level caches. Environment variable: Show more |
boolean |
|
||
Enables the Bean Validation integration. Environment variable: Show more |
boolean |
|
||
Defines the method for multi-tenancy (DATABASE, NONE, SCHEMA). The complete list of allowed values is available in the Hibernate ORM JavaDoc. The type DISCRIMINATOR is currently not supported. The default value is NONE (no multi-tenancy). Environment variable: Show more |
string |
|||
If hibernate is not auto generating the schema, and Quarkus is running in development mode then Quarkus will attempt to validate the database after startup and print a log message if there are any problems. Environment variable: Show more |
boolean |
|
||
Whether this persistence unit should be active at runtime. If the persistence unit is not active, it won’t start with the application, and accessing the corresponding EntityManagerFactory/EntityManager or SessionFactory/Session will not be possible. Note that if Hibernate ORM is disabled (i.e. Environment variable: Show more |
boolean |
|
||
Properties that should be passed on directly to Hibernate ORM.
Use the full configuration property key here,
for instance
Consider using a supported configuration property before falling back to unsupported ones. If none exists, make sure to file a feature request so that a supported configuration property can be added to Quarkus, and more importantly so that the configuration property is tested regularly. Environment variable: Show more |
Map<String,String> |
|||
Type |
Default |
|||
When set, attempts to exchange data with the database as the given version of Hibernate ORM would have, on a best-effort basis. Please note:
Environment variable: Show more |
|
|
||
The charset of the database. Used for DDL generation and also for the SQL import scripts. Environment variable: Show more |
|
|||
Select whether the database schema is generated or not. Environment variable: Show more |
string |
|
||
If Hibernate ORM should create the schemas automatically (for databases supporting them). Environment variable: Show more |
boolean |
|
||
Whether we should stop on the first error when applying the schema. Environment variable: Show more |
boolean |
|
||
The default catalog to use for the database objects. Environment variable: Show more |
string |
|||
The default schema to use for the database objects. Environment variable: Show more |
string |
|||
Whether Hibernate ORM should check on startup
that the version of the database matches the version configured on the dialect
(either the default version, or the one set through This should be set to Environment variable: Show more |
boolean |
|
||
Type |
Default |
|||
Name of the Hibernate ORM dialect. For supported databases, this property does not need to be set explicitly: it is selected automatically based on the datasource, and configured using the DB version set on the datasource to benefit from the best performance and latest features. If your database does not have a corresponding Quarkus extension, you will need to set this property explicitly. In that case, keep in mind that the JDBC driver and Hibernate ORM dialect may not work properly in GraalVM native executables. For built-in dialects, the expected value is one of the names
in the official list of dialects,
without the For third-party dialects, the expected value is the fully-qualified class name,
for example Environment variable: Show more |
string |
|
||
The storage engine to use when the dialect supports multiple storage engines. E.g. Environment variable: Show more |
string |
|||
Type |
Default |
|||
How to store timezones in the database by default
for properties of type This default may be overridden on a per-property basis using
Environment variable: Show more |
|
|
||
The optimizer to apply to identifier generators whose optimizer is not configured explicitly. Only relevant for table- and sequence-based identifier generators. Other generators, such as UUID-based generators, will ignore this setting. The optimizer is responsible for pooling new identifier values, in order to reduce the frequency of database calls to retrieve those values and thereby improve performance. Environment variable: Show more |
|
|
||
Type |
Default |
|||
The maximum size of the query plan cache. see # Environment variable: Show more |
int |
|
||
Default precedence of null values in Valid values are: Environment variable: Show more |
|
|
||
Enables IN clause parameter padding which improves statement caching. Environment variable: Show more |
boolean |
|
||
Type |
Default |
|||
The time zone pushed to the JDBC driver. See Environment variable: Show more |
string |
|||
How many rows are fetched at a time by the JDBC driver. Environment variable: Show more |
int |
|||
The number of updates (inserts, updates and deletes) that are sent by the JDBC driver at one time for execution. Environment variable: Show more |
int |
|||
Type |
Default |
|||
The size of the batches used when loading entities and collections.
Environment variable: Show more |
int |
|
||
The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one). A Environment variable: Show more |
int |
|||
Type |
Default |
|||
The maximum time before an object of the cache is considered expired. Environment variable: Show more |
||||
The maximum number of objects kept in memory in the cache. Environment variable: Show more |
long |
|||
Type |
Default |
|||
Existing applications rely (implicitly or explicitly) on Hibernate ignoring any DiscriminatorColumn declarations on joined inheritance hierarchies. This setting allows these applications to maintain the legacy behavior of DiscriminatorColumn annotations being ignored when paired with joined inheritance. Environment variable: Show more |
boolean |
|
||
Type |
Default |
|||
Logs SQL bind parameters. Setting it to true is obviously not recommended in production. Environment variable: Show more |
boolean |
|
||
Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production. Environment variable: Show more |
boolean |
|
||
Format the SQL logs if SQL log is enabled Environment variable: Show more |
boolean |
|
||
Highlight the SQL logs if SQL log is enabled Environment variable: Show more |
boolean |
|
||
Whether JDBC warnings should be collected and logged. Environment variable: Show more |
boolean |
|
||
If set, Hibernate will log queries that took more than specified number of milliseconds to execute. Environment variable: Show more |
long |
|||
Type |
Default |
|||
Select whether the database schema DDL files are generated or not. Accepted values: Environment variable: Show more |
string |
|
||
Filename or URL where the database create DDL file should be generated. Environment variable: Show more |
string |
|||
Filename or URL where the database drop DDL file should be generated. Environment variable: Show more |
string |
|||
Type |
Default |
|||
The default flushing strategy, or when to flush entities to the database in a Hibernate session: before every query, on commit, … This default can be overridden on a per-session basis with See the javadoc of Environment variable: Show more |
|
|
About the Duration format
To write duration values, use the standard You can also use a simplified format, starting with a number:
In other cases, the simplified format is translated to the
|
Want to start a PostgreSQL server on the side with Docker?
This will start a non-durable empty database: ideal for a quick experiment! |
CDI integration
If you are familiar with using Hibernate Reactive in Quarkus, you probably already have injected the Mutiny.SessionFactory
using CDI:
@Inject
Mutiny.SessionFactory sessionFactory;
This will inject the Mutiny.SessionFactory
of the default persistence unit.
Prior to Quarkus 3.0 it was also possible to inject a @RequestScoped bean for Mutiny.Session . However, the lifecycle of a reactive session does not fit the lifecycle of the CDI request context. Therefore, this bean is removed in Quarkus 3.0.
|
Automatically transitioning to Flyway to Manage Schemas
Hibernate Reactive can be used in the same application as Flyway. See this section of the Flyway extension documentation for details regarding configuration of Flyway in a reactive application.
If you have the Flyway extension installed when running in development mode, Quarkus provides a simple way to initialize your Flyway configuration using the schema generated automatically by Hibernate Reactive. See the Hibernate ORM guide for more details. |
Testing
Using Hibernate Reactive in a @QuarkusTest
is slightly more involved than using Hibernate ORM due to the asynchronous nature of the APIs and the fact that all operations need to run on a Vert.x Event Loop.
Two components are necessary to write these tests:
-
The use of
@io.quarkus.test.vertx.RunOnVertxContext
or@io.quarkus.test.TestReactiveTransaction
on the test methods -
The use of
io.quarkus.test.vertx.UniAsserter
as a test method parameter.
These classes are provided by the quarkus-test-vertx dependency.
|
A very simple example usage looks like:
@QuarkusTest
public class SomeTest {
@Inject
Mutiny.SessionFactory sessionFactory;
@Test
@RunOnVertxContext
public void testQuery(UniAsserter asserter) {
asserter.assertThat(() -> sessionFactory.withSession(s -> s.createQuery(
"from Gift g where g.name = :name").setParameter("name", "Lego").getResultList()),
list -> org.junit.jupiter.api.Assertions.assertEquals(list.size(), 1));
}
}
See the Javadoc of UniAsserter for a full description of the various methods that can be used for creating assertions.
|
You can also extend the
|
Limitations and other things you should know
Quarkus does not modify the libraries it uses; this rule applies to Hibernate Reactive as well: when using this extension you will mostly have the same experience as using the original library.
But while they share the same code, Quarkus does configure some components automatically and inject custom implementations for some extension points; this should be transparent and useful but if you’re an expert of Hibernate Reactive you might want to know what is being done.
Here’s a list of things to pay attention when using Hibernate Reactive in Quarkus:
-
Hibernate Reactive is not configurable via a
persistence.xml
file. -
This extension only considers the default persistence unit at the moment: it’s not possible to configure multiple persistence units, or even a single named persistence unit.
-
This extension cannot be used at the same time as Hibernate ORM. See https://github.com/quarkusio/quarkus/issues/13425.
-
Integration with the Envers extension is not supported.
-
Transaction demarcation cannot be done using
jakarta.transaction.Transactional
orQuarkusTransaction
; if you use Hibernate Reactive with Panache, consider using@WithTransaction
orPanache.withTransaction()
instead.
Simplifying Hibernate Reactive with Panache
The Hibernate Reactive with Panache extension facilitates the usage of Hibernate Reactive by providing active record style entities (and repositories) and focuses on making your entities trivial and fun to write in Quarkus.