在Reactor应用程序中使用R2DBC
既然Reactor已经占领了Java世界,那么就不可避免地会有一个反应式sql库。
在这篇博客中,我们将使用r2dbc与h2和reactor。
我们将从所需的依赖性开始:
<?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>
我们从r2dbc、h2 r2dbc驱动、h2二进制以及测试工具中导入spring数据。
假设这就是我们的模式。
这个模式是一个postgresql模式:
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
);
我们稍后将把它添加到test/resources/schema.sql中,用于测试目的。
另外,让我们添加一个新的模型
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;
}
}
注意isNew方法,这样版本库就可以识别对象是否应该被持久化或更新。
现在开始我们的版本库
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> {
}
让我们进行一些测试。
如前所述,上面的模式将存放在test/resources/schema.sql中。
我们将为测试的h2 db添加一些配置。我们需要确保h2将拾取postgresql接口。
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;
}
}
有了这个配置,我们创建一个模拟Postgresql数据库的H2数据库,我们创建模式以及启用R2DBC存储库的创建。
同时让我们添加一个测试:
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();
}
}