Skip to content

Commit bd557ef

Browse files
committed
document reactive repositories
1 parent 700b0ad commit bd557ef

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

documentation/src/main/asciidoc/repositories/Hibernate_Data_Repositories.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ include::Preface.adoc[]
1717
include::Repositories.adoc[]
1818
include::Configuration.adoc[]
1919
include::Pagination.adoc[]
20+
include::Reactive.adoc[]
2021

2122

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
[[reactive-repositories]]
2+
== Reactive repositories
3+
4+
Hibernate Data Repositories provides repositories backed by https://hibernate.org/reactive/[Hibernate Reactive] for use in reactive programming.
5+
The methods of a reactive repository are non-blocking, and so every operation returns a reactive stream.
6+
This is an extension to the programming model defined by Jakarta Data.
7+
8+
[NOTE]
9+
====
10+
The Jakarta Data specification has not yet defined a way to write repositories for use in reactive programming, but the spec was written to accommodate such extensions, and this capability might be standardized in a future release.
11+
====
12+
13+
In Hibernate Data Repositories we use https://smallrye.io/smallrye-mutiny/[Mutiny] to work with reactive streams.
14+
15+
[WARNING]
16+
====
17+
If and when Jakarta Data _does_ provide standard support for reactive repositories, the functionality will almost certainly be based on Java's `CompletionStage`, and not on Mutiny.
18+
====
19+
20+
In our opinion, Mutiny is a _much_ more comfortable API than `CompletionStage`.
21+
22+
=== Defining a reactive repository
23+
24+
In the following code example we notice the two requirements for a reactive repository in Hibernate Data Repositories:
25+
26+
1. there must be a resource accessor method returning the underlying `Mutiny.StatelessSession` from Hibernate Reactive, and
27+
2. the return type of every other operation is `Uni`, a reactive stream type defined by Mutiny.
28+
29+
For example, a `@Find` method which would return `Book` in a regular Jakarta Data repository must return `Uni<Book>` in a reactive repository.
30+
Similarly, lifecycle methods usually return `Uni<Void>` instead of `void`.
31+
32+
[source,java]
33+
----
34+
@Repository
35+
interface Library {
36+
37+
Mutiny.StatelessSession session();
38+
39+
@Find
40+
Uni<Book> book(String isbn);
41+
42+
@Insert
43+
Uni<Void> add(Book book);
44+
45+
@Find
46+
Uni<List<Book>> books(@By("isbn") String[] ibsns);
47+
}
48+
----
49+
50+
It's _not_ possible to mix blocking and non-blocking operations in the same repository interface.
51+
52+
=== Obtaining a reactive repository
53+
54+
To make use of our reactive repository, we'll need to bootstrap Hibernate Reactive and obtain a `Mutiny.SessionFactory`.
55+
For example, if we have a persistence unit named `example` in our `persistence.xml` file, we can obtain a `SessionFactory` like this:
56+
57+
[source,java]
58+
----
59+
Mutiny.SessionFactory factory =
60+
createEntityManagerFactory("example")
61+
.unwrap(Mutiny.SessionFactory.class);
62+
----
63+
64+
Please refer to the documentation for Hibernate Reactive for more information on this topic.
65+
66+
Once we have the `SessionFactory`, we can easily obtain a `Mutiny.StatelessSession`, and use it to instantiate our repository:
67+
68+
[source,java]
69+
----
70+
factory.withStatelessTransaction(session -> {
71+
Library library = new Library_(session);
72+
...
73+
})
74+
----
75+
76+
TIP: In Quarkus, all this is unnecessary, and you can directly inject the `Library`.
77+
78+
=== Calling a reactive repository
79+
80+
To actually make use of a reactive repository, you'll need to be familiar with the programming model of reactive streams.
81+
For this, we refer you to the Mutiny documentation, and to the documentation for Hibernate Reactive, which goes over some gotchas.
82+
83+
The most important thing to understand is that a code fragment like the following does _not_ result in any immediate interaction with the database:
84+
85+
[source,java]
86+
----
87+
Uni<Void> uni =
88+
factory.withStatelessTransaction(session -> {
89+
Library library = new Library_(session);
90+
return library.book("9781932394153");
91+
})
92+
.invoke(book -> out.println(book.title))
93+
.replaceWithVoid();
94+
----
95+
96+
This code does no more than construct a reactive stream.
97+
We can execute the stream blockingly by calling `uni.await().indefinitely()`, but that's not something we would ever do in real code.
98+
Instead, what we usually do is simply return the stream, allowing it to be executed in a non-blocking way.

0 commit comments

Comments
 (0)