1、介紹
R2DBC(Reactive Relational Database Connectivity)是在2018年Spring One Platform大會(huì)被提出來(lái)的,它旨在使用完全無(wú)阻塞驅(qū)動(dòng)程序創(chuàng)建數(shù)據(jù)庫(kù)鏈接,為SQL數(shù)據(jù)庫(kù)創(chuàng)建響應(yīng)式API。為了探索R2DBC我們將創(chuàng)建一個(gè)簡(jiǎn)單的WebFlux應(yīng)用實(shí)現(xiàn)目標(biāo)
2、項(xiàng)目配置
我們通過(guò)Spring Initializr創(chuàng)建一個(gè)新的項(xiàng)目,如下圖所示選擇我們需要的依賴。確保Spring Boot的版本大于等于2.3.0。因?yàn)樵诖税姹局蟛砰_始支持MYSQL的響應(yīng)式驅(qū)動(dòng)

project-setup.png
Maven依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
<scope>runtime</scope>
</dependency>
3、腳本準(zhǔn)備
create table test.users
(
id bigint auto_increment,
first_name varchar(50) null,
last_name varchar(50) null,
created_at datetime null,
updated_at datetime null,
constraint users_id_uindex
unique (id)
);
alter table test.users
add primary key (id);
4、應(yīng)用代碼
4.1 實(shí)體對(duì)象
注意這里用的日期類型是java.time.LocalDateTime,默認(rèn)不能使用java.sql.Date、java.util.Date、java.sql.Timestamp類型,否則會(huì)提示錯(cuò)誤。默認(rèn)支持的類型轉(zhuǎn)換參考o(jì)rg.springframework.data.r2dbc.convert.R2dbcConverters類。
@Table(value = "users")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class User {
@Id
private Long id;
@Column(value = "first_name")
private String firstName;
@Column(value = "last_name")
private String lastName;
@Column(value = "created_at")
private LocalDateTime createdAt;
@Column(value = "updated_at")
private LocalDateTime updatedAt;
}
4.2 控制層代碼
/**
* 支持增加、修改、刪除、查詢
* @date 2020-05-24
* @author 稻草鳥人
*/
@RestController
@RequestMapping("/v1")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping(path = "/users/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(code = HttpStatus.OK)
public Mono<User> getUser(@PathVariable("id") Long id) {
Mono<User> userMono = userService.find(id);
return userMono;
}
@PutMapping("/users/{id}")
public Mono<User> update(@PathVariable("id") Long id, @RequestBody User user) {
return this.userService.find(id)
.map(u -> {
u.setFirstName(user.getFirstName());
u.setLastName(user.getLastName());
return u;
})
.flatMap(u -> save(u));
}
@DeleteMapping("/users/{id}")
public Mono<Void> delete(@PathVariable("id") Long id) {
return userService.delete(id);
}
@PostMapping("/users")
public Mono<User> save(@RequestBody User user) {
return userService.save(user);
}
其他代碼不再貼了,具體參考下面的源碼部分
5、簡(jiǎn)單測(cè)試

r2dbc-update-user.png

r2dbc-create-user.png
目前只是簡(jiǎn)單的測(cè)試,后面我們做一次簡(jiǎn)單的壓測(cè),比較下非阻塞接口和同步接口的性能差異吧!