一、R2DBC是什么?
反应式编程能大大降低服务器的内存和线程需要量。但是并非所有数据库都能原生支持反应式编程。通常只有非关系型数据库支持反应式编程。为了使关系型数据库支持反应式编程,发明了R2DBC。
二、如何使用R2DBC
1. 使用Maven引入的依赖项
部分pom.xml
...
<dependencies>
<!-- Spring WebFlux依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Spring Data JPA依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2嵌入式数据库依赖项 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- R2DBC依赖项,用于使不支持反应式的数据库支持反应式 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<!-- R2DBC-h2依赖项,为了使R2DBC能使用H2数据库 -->
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- lombok依赖项,用于自动生成代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
...
2. 配置文件
application.yml
spring:
r2dbc:
# 设置R2DBC的url。这里使用的h2数据库。基于内存。创建的数据库名是testdb
url: r2dbc:h2:mem://./testdb
username: sa
password: 123456
3. Java文件
Usr.java
package model;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
@Table
@Data
@AllArgsConstructor
public class Usr {
@Id
private Integer id;
private String firstname;
private String lastname;
boolean hasId() {
return id != null;
}
}
UsrRepository.java
package repository;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
import model.Usr;
public interface UsrRepository extends ReactiveCrudRepository<Usr, Integer> {
@Query("SELECT id, firstname, lastname FROM Usr c WHERE c.lastname = :lastname")
Flux<Usr> findByLastname(String lastname);
}
UsrController.java
package controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import model.Usr;
import repository.UsrRepository;
@RestController
@RequestMapping(path = "/user", produces = "application/hal+json")
@RequiredArgsConstructor
public class UsrController {
private final UsrRepository usrRepository;
@GetMapping("/all")
public Flux<Usr> findAll() {
return usrRepository.findAll();
}
@GetMapping("/save")
public Mono<Usr> save() {
Usr user = new Usr(null, "Lindong", "Wang");
return usrRepository.save(user);
}
}
DatabaseConfig.java
package config;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.r2dbc.core.DatabaseClient;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import model.Usr;
import repository.UsrRepository;
@Configuration
@Slf4j
public class DbConfig {
@Bean
public ApplicationRunner initDatabase(DatabaseClient client, UsrRepository usrRepository) {
List<String> statements = Arrays.asList(
"DROP TABLE IF EXISTS Usr;",
"CREATE TABLE IF NOT EXISTS Usr (id SERIAL PRIMARY KEY, firstname VARCHAR(100) NOT NULL, lastname VARCHAR(100) NOT NULL);");
statements.forEach(sql -> executeSql(client, sql)
.doOnSuccess(count -> log.info("Schema created, rows updated: {}", count))
.doOnError(error -> log.error("got error: {}", error.getMessage(), error))
.subscribe()
);
return args -> getUser().flatMap(usrRepository::save).subscribe(user -> log.info("User saved: {}", user));
}
private Flux<Usr> getUser() {
return Flux.just(new Usr(null, "John", "Doe"), new Usr(null, "Jane", "Doe"));
}
private Mono<Integer> executeSql(DatabaseClient client, String sql) {
return client.sql(sql).fetch().rowsUpdated();
}
}
4. 测试代码
在控制台输入:curl localhost:8080/user/all
可以获得返回结果:[{“id”:1,“firstname”:“John”,“lastname”:“Doe”},{“id”:2,“firstname”:“Jane”,“lastname”:“Doe”}]