Using Hibernate Reactive

Hibernate Reactive 是面向 Hibernate ORM 的反应式 API,支持非阻塞数据库驱动程序以及与数据库进行反应式交互的样式。

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 并不是 Hibernate ORM 或 Hibernate ORM 的未来替代品。它是一个不同的堆栈,专为需要高并发性的反应式用例而定制。

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.

此外,使用 Quarkus REST(以前称为 RESTEasy Reactive),我们的默认 REST 层,不需要使用 Hibernate Reactive。使用 Quarkus REST 搭配 Hibernate ORM 是完全有效的,如果你不需要高并发性,也不熟悉反应式范例,则建议使用 Hibernate ORM。

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 使用了与Hibernate ORM guide中描述的大部分配置相同的注释。本指南将仅关注与 Hibernate Reactive 特有的内容。

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.

Unresolved directive in hibernate-reactive.adoc - include::{includes}/extension-status.adoc[]

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.

克隆 Git 存储库: git clone {quickstarts-clone-url},或下载 {quickstarts-archive-url}[存档]。

Clone the Git repository: git clone {quickstarts-clone-url}, or download an {quickstarts-archive-url}[archive].

解决方案位于 hibernate-reactive-quickstart directory

The solution is located in the hibernate-reactive-quickstart directory.

Setting up and configuring Hibernate Reactive

在 Quarkus 中使用 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

自动执行其他配置需求:Quarkus 将做出一些主观的选项和有根据的猜测。

Other configuration needs have been automated: Quarkus will make some opinionated choices and educated guesses.

添加以下依赖关系到您的项目:

Add the following dependencies to your project:

例如:

For instance:

pom.xml
<!-- 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>
build.gradle
// Hibernate Reactive dependency
implementation("io.quarkus:quarkus-hibernate-reactive")

Reactive SQL client for PostgreSQL
implementation("io.quarkus:quarkus-reactive-pg-client")

@Entity 为持久性对象添加注释,然后在 application.properties 中添加相关的配置属性:

Annotate your persistent objects with @Entity, then add the relevant configuration properties in application.properties:

Example 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

请注意,这些配置属性与典型的 Hibernate Reactive 配置文件中不同。它们经常会映射到 Hibernate Reactive 配置属性,但可能有不同的名称,并且不一定相互一一映射。

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.

另外,Quarkus 会自动设置许多 Hibernate Reactive 配置设置,而且通常使用较新版本的默认值。

Also, Quarkus will set many Hibernate Reactive configuration settings automatically, and will often use more modern defaults.

无法使用标准 persistence.xml 配置文件配置 Hibernate Reactive。

Configuring Hibernate Reactive using the standard persistence.xml configuration file is not supported.

请参阅 Hibernate Reactive configuration properties 部分以了解可以在 application.properties 中设置的属性列表。

See section hr-configuration-properties for the list of properties you can set in application.properties.

只要 Hibernate Reactive 扩展列在项目依赖项中,就会根据 Quarkus datasource 配置创建一个 Mutiny.SessionFactory

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.

方言将根据 Reactive SQL 客户端选择 - 除非您明确设置了一个方言。

The dialect will be selected based on the Reactive SQL client - unless you set one explicitly.

然后,您可以愉快地注入您的 Mutiny.SessionFactory

You can then happily inject your Mutiny.SessionFactory:

Example application bean using Hibernate Reactive
@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

请务必在事务中包装修改数据库的方法(例如 session.persist(entity))。

Make sure to wrap methods modifying your database (e.g. session.persist(entity)) within a transaction.

Example of an Entity
@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;
    }
}

要在 Hibernate Reactive 启动时加载 SQL 语句,请在 src/main/resources/ 目录中添加一个 import.sql 文件。此脚本可以包含任何 SQL DML 语句。请务必用分号终止每个语句。

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

有各种可选属性可用于改进会话工厂或指导 Quarkus 猜测。

There are various optional properties useful to refine your session factory or guide Quarkus' guesses.

如果没有设置任何属性,Quarkus 通常可以推断出它设置 Hibernate Reactive 所需的一切,并且会让它使用默认数据源。

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 使用您在 Hibernate ORM 中使用的相同属性。您会注意到某些属性在名称中包含 jdbc 但 Hibernate Reactive 中没有 JDBC,这些只是旧版属性名。

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.

Unresolved directive in hibernate-reactive.adoc - include::{generated-dir}/config/quarkus-hibernate-orm.adoc[]

想在 Docker 中启动 PostgreSQL 服务器吗?

Want to start a PostgreSQL server on the side with Docker?

docker run --rm --name postgres-quarkus-hibernate -e POSTGRES_USER=quarkus_test \
           -e POSTGRES_PASSWORD=quarkus_test -e POSTGRES_DB=quarkus_test \
           -p 5432:5432 postgres:14.1

这将启动一个非持久性的空数据库:非常适合快速实验!

This will start a non-durable empty database: ideal for a quick experiment!

CDI integration

如果您熟悉在 Quarkus 中使用 Hibernate Reactive,那么您可能已经使用 CDI 注入 Mutiny.SessionFactory

If you are familiar with using Hibernate Reactive in Quarkus, you probably already have injected the Mutiny.SessionFactory using CDI:

@Inject
Mutiny.SessionFactory sessionFactory;

这会注入默认持久性单元的 Mutiny.SessionFactory

This will inject the Mutiny.SessionFactory of the default persistence unit.

在 Quarkus 3.0 之前,还可以为 Mutiny.Session 注入一个 @RequestScoped bean。但是,响应会话的生命周期不符合 CDI 请求上下文的生命周期。因此,这个 bean 在 Quarkus 3.0 中已删除。

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 可以在与 Flyway 相同的应用程序中使用。有关在响应式应用程序中配置 Flyway 的详细信息,请参阅 this section of the Flyway extension documentation

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.

如果在开发模式下运行时安装了 Flyway extension,Quarkus 提供了一种简单的方法来使用 Hibernate Reactive 自动生成的模式初始化 Flyway 配置。

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.

查看 the Hibernate ORM guide 了解更多详情。

See the Hibernate ORM guide for more details.

Testing

由于 API 的异步特性以及所有操作都需要在 Vert.x 事件循环上运行,所以在 @QuarkusTest 中使用 Hibernate Reactive 比使用 Hibernate ORM 稍微复杂一些。

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.

这些类由 quarkus-test-vertx 依赖项提供。

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));
    }

}

请参阅 UniAsserter 的 Javadoc 以全面了解可用于创建断言的各种方法。

See the Javadoc of UniAsserter for a full description of the various methods that can be used for creating assertions.

您还可以扩展 io.quarkus.test.vertx.UniAsserterInterceptor 以包装注入的 UniAsserter 并自定义默认行为。例如,拦截器可用于在单独的数据库事务中执行断言方法。

You can also extend the io.quarkus.test.vertx.UniAsserterInterceptor to wrap the injected UniAsserter and customize the default behavior. For example, the interceptor can be used to execute the assert methods within a separate database transaction.:

@QuarkusTest
public class SomeTest {

   @Test
   @RunOnVertxContext
   public void testEntity(UniAsserter asserter) {
      asserter = new UniAsserterInterceptor(asserter) {
         @Override
         protected <T> Supplier<Uni<T>> transformUni(Supplier<Uni<T>> uniSupplier) {
            return () -> Panache.withTransaction(uniSupplier);
         }
      };
      asserter.execute(() -> new MyEntity().persist());
      asserter.assertEquals(() -> MyEntity.count(), 1l);
      asserter.execute(() -> MyEntity.deleteAll());
   }
}

Limitations and other things you should know

Quarkus 不会修改它使用的库;此规则也适用于 Hibernate Reactive:使用此扩展时,您几乎会与使用原始库有相同的操作体验。

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.

但是,当它们共享相同的代码时,Quarkus 会自动配置某些组件并注入某些扩展点的自定义实现;这应该是透明且有用的,但如果您是 Hibernate Reactive 专家,您可能想要了解正在做什么。

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.

以下是在 Quarkus 中使用 Hibernate Reactive 时需要注意的事项列表:

Here’s a list of things to pay attention when using Hibernate Reactive in Quarkus:

Simplifying Hibernate Reactive with Panache

Hibernate Reactive with Panache扩展通过提供活动记录样式实体(和存储库)来促进 Hibernate Reactive 的使用,专注于让编写您的实体变得轻松且有趣。

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.