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 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. |
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 not JDBC in Hibernate Reactive, these are simply legacy property names.
Configuration property fixed at build time - All other configuration properties are overridable at runtime
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: |
boolean |
|
||
Environment variable: |
string |
|||
Environment variable: |
list of string |
|||
Path to a file containing the SQL statements to execute when Hibernate ORM starts. The file is retrieved from the classpath resources,
so it 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: |
list of string |
|
||
Pluggable strategy contract for applying physical naming rules for database object names. Class name of the Hibernate PhysicalNamingStrategy implementation Environment variable: |
string |
|||
Pluggable strategy for applying implicit naming rules when an explicit name is not given. Class name of the Hibernate ImplicitNamingStrategy implementation Environment variable: |
string |
|||
Class name of a custom
Environment variable: |
string |
|||
XML files to configure the entity mapping, e.g. Environment variable: |
list of string |
|
||
Identifiers can be quoted using one of the available strategies.
Set to Environment variable: |
tooltip:none[No optimizer, resulting in a database call each and every time an identifier value is needed from the generator. Not recommended in production environments:
may result in degraded performance and/or frequent gaps in identifier values.], |
|
||
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: |
boolean |
|
||
Enables the Bean Validation integration. Environment variable: |
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: |
string |
|||
Defines the name of the datasource to use in case of SCHEMA approach. The datasource of the persistence unit will be used if not set. Environment variable: |
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: |
boolean |
|
||
If Environment variable: |
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: |
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: |
boolean |
|||
Whether metrics are published if a metrics extension is enabled. Environment variable: |
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: |
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: |
|
|||
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: |
|
|
||
The charset of the database. Used for DDL generation and also for the SQL import scripts. Environment variable: |
|
|||
Select whether the database schema is generated or not. Environment variable: |
string |
|
||
If Hibernate ORM should create the schemas automatically (for databases supporting them). Environment variable: |
boolean |
|
||
Whether we should stop on the first error when applying the schema. Environment variable: |
boolean |
|
||
The default catalog to use for the database objects. Environment variable: |
string |
|||
The default schema to use for the database objects. Environment variable: |
string |
|||
Type |
Default |
|||
Class name of the Hibernate ORM dialect. The complete list of bundled dialects is available in the Hibernate ORM JavaDoc. Setting the dialect directly is only recommended as a last resort:
most popular databases have a corresponding Quarkus extension,
allowing Quarkus to select the dialect automatically,
in which case you do not need to set the dialect at all,
though you may want to set
If your database does not have a corresponding Quarkus extension, you will need to set the dialect directly. In that case, keep in mind that the JDBC driver and Hibernate ORM dialect may not work properly in GraalVM native executables. Environment variable: |
string |
|
||
The storage engine to use when the dialect supports multiple storage engines. E.g. Environment variable: |
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: |
|
|
||
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: |
|
|
||
Type |
Default |
|||
The maximum size of the query plan cache. see # Environment variable: |
int |
|
||
Default precedence of null values in Valid values are: Environment variable: |
|
|
||
Enables IN clause parameter padding which improves statement caching. Environment variable: |
boolean |
|
||
Type |
Default |
|||
The time zone pushed to the JDBC driver. See Environment variable: |
string |
|||
How many rows are fetched at a time by the JDBC driver. Environment variable: |
int |
|||
The number of updates (inserts, updates and deletes) that are sent by the JDBC driver at one time for execution. Environment variable: |
int |
|||
Type |
Default |
|||
The size of the batches used when loading entities and collections.
Environment variable: |
int |
|
||
The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one). A Environment variable: |
int |
|||
Type |
Default |
|||
The maximum time before an object of the cache is considered expired. Environment variable: |
||||
The maximum number of objects kept in memory in the cache. Environment variable: |
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: |
boolean |
|
||
Type |
Default |
|||
Environment variable: |
string |
|||
Environment variable: |
list of string |
|||
Path to a file containing the SQL statements to execute when Hibernate ORM starts. The file is retrieved from the classpath resources,
so it 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: |
list of string |
|
||
Pluggable strategy contract for applying physical naming rules for database object names. Class name of the Hibernate PhysicalNamingStrategy implementation Environment variable: |
string |
|||
Pluggable strategy for applying implicit naming rules when an explicit name is not given. Class name of the Hibernate ImplicitNamingStrategy implementation Environment variable: |
string |
|||
Class name of a custom
Environment variable: |
string |
|||
XML files to configure the entity mapping, e.g. Environment variable: |
list of string |
|
||
Identifiers can be quoted using one of the available strategies.
Set to Environment variable: |
tooltip:none[No optimizer, resulting in a database call each and every time an identifier value is needed from the generator. Not recommended in production environments:
may result in degraded performance and/or frequent gaps in identifier values.], |
|
||
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: |
boolean |
|
||
Enables the Bean Validation integration. Environment variable: |
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: |
string |
|||
Defines the name of the datasource to use in case of SCHEMA approach. The datasource of the persistence unit will be used if not set. Environment variable: |
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: |
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: |
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: |
|
|||
Type |
Default |
|||
Class name of the Hibernate ORM dialect. The complete list of bundled dialects is available in the Hibernate ORM JavaDoc. Setting the dialect directly is only recommended as a last resort:
most popular databases have a corresponding Quarkus extension,
allowing Quarkus to select the dialect automatically,
in which case you do not need to set the dialect at all,
though you may want to set
If your database does not have a corresponding Quarkus extension, you will need to set the dialect directly. In that case, keep in mind that the JDBC driver and Hibernate ORM dialect may not work properly in GraalVM native executables. Environment variable: |
string |
|
||
The storage engine to use when the dialect supports multiple storage engines. E.g. Environment variable: |
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: |
|
|
||
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: |
|
|
||
Type |
Default |
|||
The maximum size of the query plan cache. see # Environment variable: |
int |
|
||
Default precedence of null values in Valid values are: Environment variable: |
|
|
||
Enables IN clause parameter padding which improves statement caching. Environment variable: |
boolean |
|
||
Type |
Default |
|||
The charset of the database. Used for DDL generation and also for the SQL import scripts. Environment variable: |
|
|||
Select whether the database schema is generated or not. Environment variable: |
string |
|
||
If Hibernate ORM should create the schemas automatically (for databases supporting them). Environment variable: |
boolean |
|
||
Whether we should stop on the first error when applying the schema. Environment variable: |
boolean |
|
||
The default catalog to use for the database objects. Environment variable: |
string |
|||
The default schema to use for the database objects. Environment variable: |
string |
|||
Type |
Default |
|||
The time zone pushed to the JDBC driver. See Environment variable: |
string |
|||
How many rows are fetched at a time by the JDBC driver. Environment variable: |
int |
|||
The number of updates (inserts, updates and deletes) that are sent by the JDBC driver at one time for execution. Environment variable: |
int |
|||
Type |
Default |
|||
The size of the batches used when loading entities and collections.
Environment variable: |
int |
|
||
The maximum depth of outer join fetch tree for single-ended associations (one-to-one, many-to-one). A Environment variable: |
int |
|||
Type |
Default |
|||
The maximum time before an object of the cache is considered expired. Environment variable: |
||||
The maximum number of objects kept in memory in the cache. Environment variable: |
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: |
boolean |
|
||
Type |
Default |
|||
Select whether the database schema DDL files are generated or not. Accepted values: Environment variable: |
string |
|
||
Filename or URL where the database create DDL file should be generated. Environment variable: |
string |
|||
Filename or URL where the database drop DDL file should be generated. Environment variable: |
string |
|||
Type |
Default |
|||
Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production. Environment variable: |
boolean |
|
||
Format the SQL logs if SQL log is enabled Environment variable: |
boolean |
|
||
Whether JDBC warnings should be collected and logged. Environment variable: |
boolean |
|
||
If set, Hibernate will log queries that took more than specified number of milliseconds to execute. Environment variable: |
long |
|||
Type |
Default |
|||
Logs SQL bind parameters. Setting it to true is obviously not recommended in production. Environment variable: |
boolean |
|
||
Show SQL logs and format them nicely. Setting it to true is obviously not recommended in production. Environment variable: |
boolean |
|
||
Format the SQL logs if SQL log is enabled Environment variable: |
boolean |
|
||
Whether JDBC warnings should be collected and logged. Environment variable: |
boolean |
|
||
If set, Hibernate will log queries that took more than specified number of milliseconds to execute. Environment variable: |
long |
|||
Type |
Default |
|||
Select whether the database schema DDL files are generated or not. Accepted values: Environment variable: |
string |
|
||
Filename or URL where the database create DDL file should be generated. Environment variable: |
string |
|||
Filename or URL where the database drop DDL file should be generated. Environment variable: |
string |
About the Duration format
The format for durations uses the standard You can also provide duration values starting with a number.
In this case, if the value consists only of a number, the converter treats the value as seconds.
Otherwise, |
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.
|
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:
-
it’s not possible to configure multiple persistence units at the moment
-
it’s not configurable via a
persistence.xml
file -
integration with the Envers extension is not supported
-
transaction demarcation cannot be done using
jakarta.transaction.Transactional
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.