使用 Spring Data R2DBC 异步访问 PostgreSQL 数据库

从 Spring Boot 2.x 版本(包含 Spring 5.x)开始,Pivotal 推出了异步框架 Spring Webflux,开发者开始可以在 Spring 平台上方便地编写异步非阻塞式的应用程序。但是,在该框架推出初期,只支持异步访问 MongoDB,Cassandra 等非关系型数据库。如果你想在异步应用里采用 MySQL, PostgreSQL 等关系型数据库,由于之前的数据库驱动是基于同步的 JDBC,所以会破坏掉整个系统的异步性。好消息是不久前,Spring Data 推出了一个子项目 Spring Data R2DBC,虽然项目还处于初期,并不是十分完善,但是可以让我们比较方便地以异步方式来访问关系型数据库。这里就以 PostgreSQL 为例,配置一下 Spring Data R2DBC,并使用它以异步方式来访问 PostgreSQL。

配置 Spring Data R2DBC 和 PostgreSQL

注意,要使用这个功能需要你的 Spring Boot 版本不低于 2.2.0.M6。这里使用 Gradle 构建系统,首先在 build.gradle 文件里 dependencies 中加入以下依赖:

implementation 'org.springframework.boot.experimental:spring-boot-starter-data-r2dbc'
implementation 'io.r2dbc:r2dbc-postgresql:1.0.0.M7'

由于这个库还处于初期开发阶段,并不十分完善,所以 Spring Boot 还暂不支持自动配置,需要我们自定义一个配置类进行配置。为了以后修改方便,我们可以先把数据库相关信息写在 application.properties 里面,然后通过 @Value 注解在代码里调用。

spring.data.postgres.host=127.0.0.1
spring.data.postgres.port=5432
spring.data.postgres.database=test_db
spring.data.postgres.username=root
spring.data.postgres.password=password

然后我们可以写一个配置类,标注 @Configuration 注解,来手动定义 PostgreSQL 的配置。

@Configuration
public class DatabaseConfiguration {
    @Value(value = "${spring.data.postgres.host}")
    private String host;

    @Value("${spring.data.postgres.port}")
    private Integer port;

    @Value("${spring.data.postgres.database}")
    private String database;

    @Value("${spring.data.postgres.username}")
    private String username;

    @Value("${spring.data.postgres.password}")
    private String password;

    @Bean
    PostgresqlConnectionFactory connectionFactory() {
        PostgresqlConnectionConfiguration config = PostgresqlConnectionConfiguration.builder()
                .host(host)
                .port(port)
                .database(database)
                .username(username)
                .password(password)
                .build();
        return new PostgresqlConnectionFactory(config);
    }
}

编写实体,repository 和 Controller

我们的 Spring Data R2DBC 和 PostgreSQL 已经手动配置好了。现在我们可以很方便地用之前 Spring Data JPA 类似的写法来编写实体和对应的 repository,需要注意的是,Spring Data R2DBC 暂时还不支持方法名推导,所以每一个 repository 方法都需要使用 @Query 注解配合查询语句使用。

这里以一个简单的 Video 实体作为例子,注意使用了 Lombok 的注解 @Data 来减少样板代码。

@Data
@Table("video")
public class Video {
    @Id
    Long id;

    String title;
}

注意 repository 的写法,返回类型使用了 Flux 包装起来,Flux 和 Mono 是异步编程框架 Reactor 中的两种基本类型,Flux 表示空或多个结果,Mono 表示空或一个结果。由于 Spring Webflux 是基于 Reactor 构建的,所以如果要使用 Webflux 框架,就会经常与这两种类型打交道,下面写 Controller 也同样要使用这两种类型。

@Repository
public interface VideoRepository extends R2dbcRepository {
    @Query("SELECT v FROM VIDEO v")
    Flux

Controller 的写法除了返回类型需要用 Flux 或 Mono 包装,与之前的经典写法基本相同。Webflux 也提供另外一种函数式的写法,但是对于习惯 Spring MVC 写法的开发者来说,显然这种写法更清晰,更容易上手。

@RestController
@RequestMapping("/videos")
public class VideoController {
    private VideoRepository videoRepository;

    @Autowired
    VideoController(VideoRepository videoRepository) {
        this.videoRepository = videoRepository;
    }

    @GetMapping("/")
    Flux

一个简单的使用 Spring Data R2DBC 异步访问 PostgreSQL 的例子就完成了,只实现了一个查询数据表所有记录的功能。可以看到,通过 Spring Data R2DBC 我们可以很方便地使用与之前类似的写法去异步访问关系型数据库。虽然目前还需要我们手动配置,而且功能也比较简陋,比如不支持方法名推导等,但随着这个项目的不断完善,这些问题应该会逐步被解决的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注