Since Reactor has taken over the Java world it was inevitable the a reactive sql library would be there.
In this blog we shall use r2dbc with h2 and reactor.
We shall start with the dependencies needed.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.2</version> </parent> <groupId>com.gkatzioura</groupId> <artifactId>r2dbc-reactor</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-r2dbc</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.r2dbc</groupId> <artifactId>r2dbc-h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
We imported spring data from r2dbc, the h2 r2dbc driver, the h2 binary as well as the test utils.
Supposing that this is our schema.
This schema is a postgresql schema.
create table order_request ( id uuid NOT NULL constraint or_id_pk primary key, created_by varchar, created timestamp default now() not null, updated timestamp default now() not null );
We shall add it later to test/resources/schema.sql for testing purposes.
Also letβs add a new model
package com.gkatzioura.r2dbc.model;
import java.time.LocalDateTime;
import java.util.UUID;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Persistable;
import org.springframework.data.relational.core.mapping.Table;
@Table("order_request")
public class OrderRequest implements Persistable<UUID> {
@Id
private UUID id;
private String createdBy;
private LocalDateTime created;
private LocalDateTime updated;
public void setId(UUID id) {
this.id = id;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
public LocalDateTime getUpdated() {
return updated;
}
public void setUpdated(LocalDateTime updated) {
this.updated = updated;
}
@Override
public UUID getId() {
return id;
}
@Override
public boolean isNew() {
return created == null;
}
}Pay attention to isNew method. This way the repository can identify if the object should be persisted or updated.
Now onwards to our Repository
package com.gkatzioura.r2dbc.repository;
import java.util.UUID;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import com.gkatzioura.r2dbc.model.OrderRequest;
public interface OrderRepository extends ReactiveCrudRepository<OrderRequest, UUID> {
}Letβs put some tests.
As mentioned the schema above will reside in test/resources/schema.sql
We shall add some configuration for the test h2 db. We need to make sure that h2 will pickup the postgresql interface.
package com.gkatzioura.r2dbc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.r2dbc.connection.init.CompositeDatabasePopulator;
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.spi.ConnectionFactory;
@Configuration
@EnableR2dbcRepositories
public class H2ConnectionConfiguration extends AbstractR2dbcConfiguration {
@Override
public ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(
io.r2dbc.h2.H2ConnectionConfiguration.builder()
.url("mem:testdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;")
.build()
);
}
@Bean
public ConnectionFactoryInitializer initializer() {
var initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory());
var databasePopulator = new CompositeDatabasePopulator();
databasePopulator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
initializer.setDatabasePopulator(databasePopulator);
return initializer;
}
}With this configuration we create a H2 database simulating a Postgresql DB, we create the schemas as well as enable the creation of the R2DBC repositories.
Also letβs add a test.
package com.gkatzioura.r2dbc.repository;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.gkatzioura.r2dbc.H2ConnectionConfiguration;
import com.gkatzioura.r2dbc.model.OrderRequest;
import reactor.test.StepVerifier;
@ExtendWith({SpringExtension.class})
@Import({H2ConnectionConfiguration.class})
class OrderRepositoryTest {
@Autowired
private OrderRepository orderRepository;
@Test
void testSave() {
UUID id = UUID.randomUUID();
OrderRequest orderRequest = new OrderRequest();
orderRequest.setId(id);
orderRequest.setCreatedBy("test-user");
var persisted = orderRepository.save(orderRequest)
.map(a -> orderRepository.findById(a.getId()))
.flatMap(a -> a.map(b -> b.getId()));
StepVerifier.create(persisted).expectNext(id).verifyComplete();
}
}Thatβs it, you can find the code on github.
Published on Java Code Geeks with permission by Emmanouil Gkatziouras, partner at our JCG program. See the original article here: Using R2DBC with a Reactor Application Opinions expressed by Java Code Geeks contributors are their own. |
Thank you!
We will contact you soon.
Emmanouil GkatziourasSeptember 1st, 2021Last Updated: August 25th, 2021

This site uses Akismet to reduce spam. Learn how your comment data is processed.