Querying R2DBC
The querydsl-r2dbc module provides reactive, non-blocking database access
built on R2DBC and Project Reactor.
The API mirrors the SQL module but returns Mono and Flux types instead of
blocking results.
Maven Integration
Add the following dependencies to your Maven project:
<dependency>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-r2dbc</artifactId>
<version>7.1</version>
</dependency>
You also need an R2DBC driver for your database, for example:
<!-- PostgreSQL R2DBC driver -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
Code generation for the query types works exactly like the
SQL module — use the
querydsl-maven-plugin or querydsl-sql-codegen to export your schema.
Configuration
Configuration is done via com.querydsl.r2dbc.Configuration, which takes a
Querydsl SQL dialect as an argument:
SQLTemplates templates = new PostgreSQLTemplates();
Configuration configuration = new Configuration(templates);
The same SQLTemplates classes used by the SQL module are reused for R2DBC.
See the SQL tutorial for the
full list of available dialects.
Connection Provider
R2DBC queries require an R2DBCConnectionProvider to obtain reactive
connections. The simplest way to create one is from a ConnectionFactory:
ConnectionFactory connectionFactory = ...;
R2DBCConnectionProvider provider = R2DBCConnectionProvider.from(connectionFactory);
The provider manages the connection lifecycle, automatically acquiring and releasing connections for each operation.
Creating the Query Factory
R2DBCQueryFactory is the main entry point for constructing queries:
R2DBCQueryFactory queryFactory = new R2DBCQueryFactory(configuration, provider);
Database-specific query factories are also available:
R2DBCPostgreQueryFactory— PostgreSQL-specific featuresR2DBCMySQLQueryFactory— MySQL-specific features (e.g.INSERT IGNORE,ON DUPLICATE KEY UPDATE)R2DBCServerQueryFactory— SQL Server-specific features
R2DBCPostgreQueryFactory queryFactory = new R2DBCPostgreQueryFactory(provider);
Querying
Queries return reactive types from Project Reactor.
Fetching Multiple Results
QCustomer customer = QCustomer.customer;
Flux<String> lastNames = queryFactory.select(customer.lastName)
.from(customer)
.where(customer.firstName.eq("Bob"))
.fetch();
lastNames.subscribe(name -> System.out.println(name));
Fetching a Single Result
Mono<Customer> bob = queryFactory.selectFrom(customer)
.where(customer.firstName.eq("Bob"))
.fetchFirst();
Using Tuples
Flux<Tuple> rows = queryFactory.select(customer.firstName, customer.lastName)
.from(customer)
.fetch();
rows.subscribe(row -> {
System.out.println(row.get(customer.firstName));
System.out.println(row.get(customer.lastName));
});
Joins
Joins work the same way as in the SQL module:
QCustomer customer = QCustomer.customer;
QCompany company = QCompany.company;
Flux<Tuple> results = queryFactory
.select(customer.firstName, customer.lastName, company.name)
.from(customer)
.innerJoin(customer.company, company)
.fetch();
Ordering and Paging
Flux<Customer> results = queryFactory.selectFrom(customer)
.orderBy(customer.lastName.asc(), customer.firstName.asc())
.limit(10)
.offset(20)
.fetch();
Subqueries
QCustomer customer = QCustomer.customer;
QCustomer customer2 = new QCustomer("customer2");
Flux<Tuple> results = queryFactory.select(customer.all())
.from(customer)
.where(customer.status.eq(
SQLExpressions.select(customer2.status.max()).from(customer2)))
.fetch();
Data Manipulation Commands
Insert
QSurvey survey = QSurvey.survey;
Mono<Long> insertCount = queryFactory.insert(survey)
.columns(survey.id, survey.name)
.values(3, "Hello")
.execute();
Using the set method:
Mono<Long> insertCount = queryFactory.insert(survey)
.set(survey.id, 3)
.set(survey.name, "Hello")
.execute();
Update
Mono<Long> updateCount = queryFactory.update(survey)
.where(survey.name.eq("XXX"))
.set(survey.name, "S")
.execute();
Delete
Mono<Long> deleteCount = queryFactory.delete(survey)
.where(survey.name.eq("XXX"))
.execute();
MySQL-Specific Features
The R2DBCMySQLQueryFactory provides MySQL-specific insert variants:
R2DBCMySQLQueryFactory mysqlFactory = new R2DBCMySQLQueryFactory(configuration, provider);
// INSERT IGNORE
mysqlFactory.insertIgnore(survey)
.set(survey.id, 3)
.set(survey.name, "Hello")
.execute();
// INSERT ... ON DUPLICATE KEY UPDATE
mysqlFactory.insertOnDuplicateKeyUpdate(survey, "name = VALUES(name)")
.set(survey.id, 3)
.set(survey.name, "Hello")
.execute();
Comparison with the SQL Module
| Feature | SQL Module | R2DBC Module |
|---|---|---|
| Return types | List<T>, T |
Flux<T>, Mono<T> |
| Connection | java.sql.Connection |
io.r2dbc.spi.Connection |
| Factory class | SQLQueryFactory |
R2DBCQueryFactory |
| Query class | SQLQuery |
R2DBCQuery |
| Blocking | Yes | No |
| Configuration | com.querydsl.sql.Configuration |
com.querydsl.r2dbc.Configuration |
| Templates | Shared SQLTemplates |
Shared SQLTemplates |