Skip to content

Commit

Permalink
Document how to use Flyway in reactive applications
Browse files Browse the repository at this point in the history
  • Loading branch information
yrodiere committed Apr 26, 2024
1 parent 24faf1c commit 69ad3fd
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 23 deletions.
14 changes: 14 additions & 0 deletions docs/src/main/asciidoc/datasource.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ Until now, the configuration has been the same regardless of whether you are usi
When you have defined the database kind and the credentials, the rest depends on what type of driver you are using.
It is possible to use JDBC and a reactive driver simultaneously.

[[jdbc-datasource]]
==== JDBC datasource

JDBC is the most common database connection pattern, typically needed when used in combination with non-reactive Hibernate ORM.
Expand Down Expand Up @@ -294,6 +295,7 @@ AgroalDataSource defaultDataSource;
In the above example, the type is `AgroalDataSource`, a `javax.sql.DataSource` subtype.
Because of this, you can also use `javax.sql.DataSource` as the injected type.

[[reactive-datasource]]
==== Reactive datasource

Quarkus offers several reactive clients for use with a reactive datasource.
Expand Down Expand Up @@ -325,10 +327,22 @@ Be aware that setting the pool size too low might cause some requests to time ou

For more information about pool size adjustment properties, see the <<reactive-configuration>> section.

[[jdbc-and-reactive-datasources-simultaneously]]
==== JDBC and reactive datasources simultaneously

When a JDBC extension - along with Agroal - and a reactive datasource extension handling the given database kind are included, they will both be created by default.

If you want to use them both,
make sure to set both <<jdbc-datasource,JDBC>> and <<reactive-datasource,reactive>> configuration,
for example:

[source,properties]
----
%prod.quarkus.datasource.reactive.url=postgresql:///your_database
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/hibernate_orm_test
----

If you do not want to have both a JDBC datasource and a reactive datasource created, use the following configuration.
* To disable the JDBC datasource explicitly:
+
[source, properties]
Expand Down
17 changes: 17 additions & 0 deletions docs/src/main/asciidoc/flyway.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,23 @@ When using Flyway together with Hibernate ORM, you can use the Dev UI to generat

You can find more information about this feature in the xref:hibernate-orm.adoc#flyway[Hibernate ORM guide].

[[reactive-datasources]]
== Flyway and Reactive datasources

Flyway internally relies on a JDBC datasource,
whereas reactive use cases will rely on xref:reactive-sql-clients.adoc[reactive SQL clients],
either directly or through xref:hibernate-reactive.adoc[Hibernate Reactive].
This is not a problem in Quarkus,
because xref:datasource.adoc#jdbc-and-reactive-datasources-simultaneously[a single configured datasource can be made available both through reactive clients and JDBC].

To use Flyway on a datasource you otherwise access reactively,
simply make sure to configure that datasource
both as xref:datasource.adoc#jdbc-datasource[JDBC]
and xref:datasource.adoc#reactive-datasource[reactive].
This involves in particular adding dependencies to Quarkus extensions
for both the JDBC driver and the reactive client,
for instance `quarkus-jdbc-postgresql` *and* `quarkus-reactive-pg-client`.

== Flyway on Kubernetes
Sometimes, it's helpful not to execute Flyway initialization on each application startup. One such example is when deploying

Expand Down
16 changes: 16 additions & 0 deletions docs/src/main/asciidoc/hibernate-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,22 @@ This will inject the `Mutiny.SessionFactory` of the default persistence unit.

NOTE: 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.

[[flyway]]
== Automatically transitioning to Flyway to Manage Schemas

Hibernate Reactive can be used in the same application as Flyway.
See xref:flyway.adoc#reactive-datasources[this section of the Flyway extension documentation]
for details regarding configuration of Flyway in a reactive application.

[TIP]
====
If you have the xref:flyway.adoc[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 xref:hibernate-orm.adoc#flyway[the Hibernate ORM guide] for more details.
====

[[testing]]
=== Testing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.hibernate.reactive.mutiny.Mutiny;

import io.agroal.api.AgroalDataSource;
import io.quarkus.agroal.DataSource;
import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.mysqlclient.MySQLPool;
import io.vertx.mutiny.sqlclient.Row;
Expand All @@ -28,15 +27,14 @@ public class HibernateReactiveMySQLTestEndpoint {
MySQLPool mysqlPool;

@Inject
@DataSource("blocking")
AgroalDataSource blockingDS;
AgroalDataSource jdbcDataSource;

@GET
@Path("/blockingFind")
public GuineaPig blockingFind() throws SQLException {
@Path("/jdbcFind")
public GuineaPig jdbcFind() throws SQLException {
final GuineaPig expectedPig = new GuineaPig(6, "Iola");
populateDBBlocking();
return selectBlocking(6);
populateDBJdbc();
return selectJdbc(6);
}

@GET
Expand Down Expand Up @@ -102,8 +100,8 @@ private Uni<RowSet<Row>> populateDB() {
.flatMap(junk -> mysqlPool.preparedQuery("INSERT INTO Pig (id, name) VALUES (5, 'Aloi')").execute());
}

private void populateDBBlocking() throws SQLException {
Connection connection = blockingDS.getConnection();
private void populateDBJdbc() throws SQLException {
Connection connection = jdbcDataSource.getConnection();
connection.prepareStatement("DELETE FROM Pig").execute();
connection.prepareStatement("INSERT INTO Pig (id, name) VALUES (6, 'Iola')").execute();
connection.close();
Expand All @@ -121,8 +119,8 @@ private Uni<String> selectNameFromId(Integer id) {
});
}

private GuineaPig selectBlocking(Integer id) throws SQLException {
Connection connection = blockingDS.getConnection();
private GuineaPig selectJdbc(Integer id) throws SQLException {
Connection connection = jdbcDataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, name FROM Pig WHERE id = ?");
statement.setInt(1, id);
ResultSet rowSet = statement.executeQuery();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
# Reactive datasource config
# Reactive+JDBC datasource config
quarkus.datasource.db-kind=mysql
quarkus.datasource.username=hibernate_orm_test
quarkus.datasource.password=hibernate_orm_test
quarkus.datasource.reactive.url=${reactive-mysql.url}

# Blocking datasource config
quarkus.datasource.blocking.db-kind=mysql
quarkus.datasource.blocking.username=hibernate_orm_test
quarkus.datasource.blocking.password=hibernate_orm_test
quarkus.datasource.blocking.jdbc.url=${mysql.jdbc.url}
quarkus.datasource.blocking.jdbc=true
quarkus.datasource.blocking.jdbc.max-size=1
quarkus.datasource.jdbc.url=${mysql.jdbc.url}
quarkus.datasource.jdbc.max-size=1

# Hibernate config
#quarkus.hibernate-orm.log.sql=true
# We'll use Flyway
quarkus.hibernate-orm.database.generation=none

# Check that one can use Flyway alongside Hibernate Reactive
quarkus.flyway.blocking.migrate-at-start=true
quarkus.flyway.migrate-at-start=true
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public void reactiveFindMutiny() {
}

@Test
public void blockingFind() {
public void jdbcFind() {
RestAssured.when()
.get("/tests/blockingFind")
.get("/tests/jdbcFind")
.then()
.body(is("{\"id\":6,\"name\":\"Iola\"}"));
}
Expand Down

0 comments on commit 69ad3fd

Please sign in to comment.