WebFlux 操作 MySQL 是种什么体验?

不知不觉中,我们的 WebFlux 系列已经整到第 11 篇啦。如果小伙伴们还没看过前面的文章,记得先看一下哦,这有助于理解本文。

  1. 挖一个大坑,WebFlux 开搞!
  2. WebFlux 前置知识(一)
  3. WebFlux 前置知识(二)
  4. WebFlux 前置知识(三)
  5. WebFlux 前置知识(四)
  6. 异步 Servlet 都不懂,谈何 WebFlux?
  7. WebFlux 初体验
  8. 服务端主动推送数据,除了 WebSocket 你还能想到啥?
  9. 用 WebFlux 写个 CURD 是什么体验?
  10. WebFlux 中的请求地址路由怎么玩?

好啦,开始今天的正文。

前面我们用 WebFlux 已经写了一个 CURD 了,不过数据库用的是 MongoDB。很多人对 WebFlux 持怀疑态度,包括松哥之前发文章的时候,还有人在说不能连接 MySQL 的 WebFlux 是没有任何意义的!这句话没错,但是我们也要看到 WebFlux 正处于一个高速发展的时期,所有不可能的事情都会变得可能,所有以前没有的功能以后都会有,WebFlux 的变化速度是肉眼可见的。

比如我们今天要介绍的 R2DBC 就能在一定程度上打消一些人的疑虑,虽然这个工具还不是特别完美,但是我们看到了 WebFlux 在努力解决这些存在的问题,我们也有理由相信 WebFlux 未来会越来越好。

好啦,不吹了,还是来看点实际的东西吧。

1.什么是 R2DBC?

首先大家要知道,我们最常使用的 JDBC 其实是同步的,而我们使用 WebFlux 的目的是为了通过异步的方式来提高服务端的响应效率,WebFlux 虽然实现了异步,但是由于 JDBC 还是同步的,而大部分应用都是离不开数据库的,所以其实效率本质上还是没有提升。

那么怎么办呢?有没有异步的 JDBC 呢?有!

目前市面上异步 JDBC 主要是两种:

  • ADAB:ADBA 是 Oracle 主导的 Java 异步数据库访问的标准 API,它将会集成于未来的 Java 标准发行版中。但是目前发展比较慢,只提供 OpenJDK 的沙盒特性供开发者研究之用。
  • R2DBC:R2DBC 是 Spring 官方在 Spring5 发布了响应式 Web 框架 Spring WebFlux 之后急需能够满足异步响应的数据库交互 API,不过由于缺乏标准和驱动,Pivotal 团队开始自己研究响应式关系型数据库连接 Reactive Relational Database Connectivity,并提出了 R2DBC 规范 API 用来评估可行性并讨论数据库厂商是否有兴趣支持响应式的异步非阻塞驱动程序。最早只有 PostgreSQL 、H2、MSSQL 三家数据库厂商,不过现在 MySQL 也加入进来了,这是一个极大的利好。目前 R2DBC 的最新版本是 0.9.0.RELEASE。

需要注意的是,这两个都不是对原来 JDBC 的补充,都是打算重新去设计数据库访问方案!

好了,现在大家对 R2DBC 有一个基本的认知了,接下来我们就通过一个简单的例子,我们一起来体验一把如何通过 R2DBC 来操作 MySQL 数据库。

2.代码实践

2.1 创建项目

首先我们来创建一个 Spring Boot 项目,引入 WebFlux 和 R2DBC 依赖,如下图:

image

项目创建成功后,pom.xml 文件中会自动加入 R2DBC 相关的依赖,如下:

<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>dev.miku</groupId>
    <artifactId>r2dbc-mysql</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

接下来我们在 application.properties 中配置数据库的连接信息,注意这次的配置和之前的有些不同:

spring.r2dbc.url=r2dbcs:mysql://localhost:3306/test01
spring.r2dbc.username=root
spring.r2dbc.password=123

配置文件除了属性的 key 不同之外,数据库的连接协议也从 jdbc 变为 r2dbc 了。

OK,如此,我们的准备工作就算完成了。

2.2 数据库脚本

我们准备一个简单的数据表,如下:

image

这个脚本很简单,应该不用我提供了吧。

2.3 CURD

我们首先来提供一个实体类,如下:

public class User {
    @Id
    private Long id;
    private String username;
    private String address;
    //省略 getter/setter
}

然后我们需要一个 UserRepository 接口,这个接口直接继承自 ReactiveCrudRepository 即可,这跟之前 MongoDB 的玩法比较类似。

public interface UserRepository extends ReactiveCrudRepository<User,Long> {

}

接下来我们来定义 User 表的处理器,这个也跟之前 MongoDB 中的差不多,如下:

import static java.lang.Long.parseLong;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.ServerResponse.notFound;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

@Component
public class UserHandler {

    @Autowired
    UserRepository userRepository;

    public Mono<ServerResponse> getAllUsers(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.findAll(), User.class);
    }

    public Mono<ServerResponse> addUser(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.saveAll(serverRequest.bodyToMono(User.class)), User.class);
    }

    public Mono<ServerResponse> deleteUser(ServerRequest serverRequest) {
        return userRepository.findById(parseLong(serverRequest.pathVariable("id")))
                .flatMap(user -> userRepository.delete(user).then(ok().build()))
                .switchIfEmpty(notFound().build());
    }
}

最后我们再来配置请求地址路由,如下:

@Configuration
public class RouterConfiguration {
    @Bean
    RouterFunction<ServerResponse> userRouterFunction(UserHandler userHandler) {
        return RouterFunctions.nest(RequestPredicates.path("/user"),
                RouterFunctions.route(RequestPredicates.GET("/"), userHandler::getAllUsers)
                        .andRoute(RequestPredicates.POST("/"), userHandler::addUser)
                        .andRoute(RequestPredicates.DELETE("/{id}"), userHandler::deleteUser));
    }
}

这一块其实都没啥好说的,如果大家感到困惑,可以参考我们前两篇文章中的讲解。

3.测试

最后我们来简单测试下。

查询:

image

添加:

image

更新:

image

有 id 并且 id 已经存在,默认就是更新。

删除:

删除成功响应 200:

删除成功响应 200

删除失败响应 404:

删除失败响应 404

好啦,这就是一个简单的 WebFlux 操作关系型数据库的案例,关于 WebFlux 的更多其他用法,跟随松哥一起来慢慢解剖吧~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容