Using Hibernate Reactive

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

Hibernate Reactive 并不是 Hibernate ORM 或 Hibernate ORM 的未来替代品。它是一个不同的堆栈,专为需要高并发性的反应式用例而定制。 此外,使用 Quarkus REST(以前称为 RESTEasy Reactive),我们的默认 REST 层,不需要使用 Hibernate Reactive。使用 Quarkus REST 搭配 Hibernate ORM 是完全有效的,如果你不需要高并发性,也不熟悉反应式范例,则建议使用 Hibernate ORM。

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

该技术被认为是 {extension-status}。 有关可能状态的完整列表,请查看我们的 FAQ entry.

Solution

我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。

克隆 Git 存储库: git clone $${quickstarts-base-url}.git,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。

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

Setting up and configuring Hibernate Reactive

在 Quarkus 中使用 Hibernate Reactive 时,您需要:

  • application.properties 中添加您的配置设置

  • 像往常一样用 @Entity 和任何其他映射注释为实体加注释

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

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

例如:

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 中添加相关的配置属性:

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 不同于 Hibernate ORM 配置的唯一属性

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

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

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

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

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

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

然后,您可以愉快地注入您的 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 注入会话工厂并尽情玩耍
2 .withTransaction() 将在提交时自动刷新

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

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 语句。请务必用分号终止每个语句。

这可用于为测试或演示准备好数据集。

Hibernate Reactive configuration properties

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

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

此处列出的配置属性允许您覆盖这些默认值,并自定义和调整各个方面。

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

Unresolved include directive in modules/ROOT/pages/hibernate-reactive.adoc - include::../../../target/quarkus-generated-doc/config/quarkus-hibernate-orm.adoc[]

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

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

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

CDI integration

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

@Inject
Mutiny.SessionFactory sessionFactory;

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

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

Automatically transitioning to Flyway to Manage Schemas

Hibernate Reactive 可以在与 Flyway 相同的应用程序中使用。有关在响应式应用程序中配置 Flyway 的详细信息,请参阅 this section of the Flyway extension documentation

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

Testing

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

编写这些测试需要两个组件:

  • 在测试方法上使用 @io.quarkus.test.vertx.RunOnVertxContext@io.quarkus.test.TestReactiveTransaction

  • io.quarkus.test.vertx.UniAsserter 用作测试方法参数

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

一个非常简单的用例如下所示:

@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 以全面了解可用于创建断言的各种方法。

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

@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 会自动配置某些组件并注入某些扩展点的自定义实现;这应该是透明且有用的,但如果您是 Hibernate Reactive 专家,您可能想要了解正在做什么。

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

Simplifying Hibernate Reactive with Panache

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