1. 前言

在使用 R2DBC 操作 MySQL 数据库 一文中初步介绍了r2dbc-mysql的使用。但是借助于DatabaseClient操作MySQL,过于初级和底层,不利于开发。今天就利用Spring Data R2DBC来演示Spring 数据存储抽象(Spring Data Repository)风格的R2DBC数据库操作。

请注意:目前Spring Data R2DBC虽然已经迭代了多个正式版,但是仍然处于初级阶段,还不足以运用到生产中。不过未来可期,值得研究学习。

2. Spring Data R2DBC

Spring Data R2DBC提供了基于R2DBC反应式关系数据库驱动程序的流行的Repository抽象。但是这并不是一个 ORM 框架,你可以把它看做一个数据库访问的抽象层或者R2DBC的客户端程序。它不提供ORM框架具有的缓存、懒加载等诸多特性,但它抽象了数据库和对象的抽象映射关系,具有轻量级、易用性的特点。

2.1 版本对应关系

胖哥总结了截至目前Spring Data R2DBCSpring Framework的版本对应关系:

Spring Data R2DBC Spring Framework
1.0.0.RELEASE 5.2.2.RELEASE
1.1.0.RELEASE 5.2.6.RELEASE
1.1.1.RELEASE 5.2.7.RELEASE
1.1.2.RELEASE 5.2.8.RELEASE

一定要注意版本对应关系,避免不兼容的情况。

3. 基础依赖

上次我没有引用R2DBC连接池,这次我将尝试使用它。主要依赖如下 ,这里我还集成了Spring Webflux:

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-data-r2dbcartifactId>dependency>

<dependency>    <groupId>io.r2dbcgroupId>    <artifactId>r2dbc-poolartifactId>dependency>

<dependency>    <groupId>dev.mikugroupId>    <artifactId>r2dbc-mysqlartifactId>dependency>

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-data-jdbcartifactId>dependency>

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-webfluxartifactId>dependency>

这里我采用的是 Spring Boot 2.3.2.RELEASE

4. 配置

上次我们采用的是JavaConfig风格的配置,只需要向Spring IoC注入一个ConnectionFactory。这一次我将尝试在application.yaml中配置R2DBC的必要参数。

spring:  r2dbc:    url: r2dbcs:mysql://127.0.0.1:3306/r2dbc    username: root    password: 123456

以上就是R2DBC的主要配置。特别注意的是spring.r2dbc.url的格式,根据数据库的不同写法是不同的,要看驱动的定义,这一点非常重要。连接池这里使用默认配置即可,不用显式定义。

5. 编写业务代码

接下来就是编写业务代码了。这里我还尝试使用DatabaseClient来执行了DDL语句创建了client_user表,感觉还不错。

@AutowiredDatabaseClient databaseClient;

@Testvoid doDDL() {

    List ddl = Collections.unmodifiableList(Arrays.asList("drop table if exists client_user;", "create table client_user(user_id varchar(64) not null primary key,nick_name varchar(32),phone_number varchar(16),gender tinyint default 0) charset = utf8mb4;"));    ddl.forEach(sql -> databaseClient.execute(sql)            .fetch()            .rowsUpdated()            .as(StepVerifier::create)            .expectNextCount(1)            .verifyComplete());}

5.1 声明数据库实体

熟悉Spring Data JPA的同学应该很轻车熟路了。

/** *  the client user type * * @author felord.cn */@Data@Tablepublic class ClientUser implements Serializable {    private static final long serialVersionUID = -558043294043707772L;    @Id    private String userId;    private String nickName;    private String phoneNumber;    private Integer gender;}

5.2 声明 CRUD 接口

上面实体类中的@Table注解是有说法的,当我们的操作接口继承的是ReactiveCrudRepository 或者ReactiveSortingRepository时,需要在实体类上使用@Table注解,这也是推荐的用法。

public interface ReactiveClientUserSortingRepository extends ReactiveSortingRepository<ClientUser,String> {

}

当然实体类不使用@Table注解标记时,我们还可以继承R2dbcRepository接口。然后ReactiveClientUserSortingRepository将提供一些操作数据库的方法。

Repository提供的一些默认操作数据库的方法

然后Spring Data JPA怎么写,这里也差不多怎么写,但是有些功能现在还没有得到支持,比如上面提到的分页,还有主键策略等。

类似PagingAndSortingRepository的反应式分页功能接口目前还没有实装,会在未来的版本集成进来。

5.3 实际操作

接下来我们就要通过R2DBC实际操作MySQL数据库了。按照我们传统的逻辑写了如下的新增逻辑:

ClientUser clientUser = new ClientUser();

clientUser.setGender(2);clientUser.setNickName("r2dbc");clientUser.setPhoneNumber("9527");clientUser.setUserId("snowflake");

Mono save = reactiveClientUserSortingRepository.save(clientUser);

结果数据库并没有写入数据。这时因为r2dbc-mysql不能被直接使用,只能由客户端去实现并委托给客户端去操作。

这也是R2DBC的设计原则,R2DBC 的目标是最小化 SPI 平面,目的是消除数据库之间的差异部分,并使得整个数据库完全具有反应式和背压。它主要用作客户端库使用的驱动程序 SPI,而不打算直接在应用程序代码中使用。

所以这里我们可以借助于reactor-test测试库去执行一下,改写为:

reactiveClientUserSortingRepository.save(clientUser)        .log()        .as(StepVerifier::create)        .expectNextCount(1)        .verifyComplete();

但是依然不能执行成功,提示update table [client_user]. Row with Id [snowflake] does not exist ,也就是说期望执行的是新增但是实际执行的是更新,由于数据库找不到主键为snowflake的记录就报了错。这里为什么是更新呢?

这时因为实体类在进行新增时会判断主键是否填充,如果没有填充就认为是新数据,采取真正的新增操作,主键需要数据库来自动填充;如果主键存在值则认为是旧数据则调用更新操作。胖哥同Spring Data R2DBC的项目组沟通后并没有得到友好的解决方案,不过我已经找到了方法,这里先留个坑。

那么该如何新增一条数据呢?我们只能借助于@Query注解来编写一条SQL写入了:

@Modifying@Query("insert into client_user (user_id,nick_name,phone_number,gender) values (:userId,:nickName,:phoneNumber,:gender)")Mono addClientUser(String userId, String nickName, String phoneNumber, Integer gender);

当添加了@Modifying后,返回值可以从MonoMono或者Mono任意一种选择。

reactiveClientUserSortingRepository        .addClientUser("snowflake",                "r2dbc",                "132****155",                0)        .as(StepVerifier::create)        .expectNextCount(1)        .verifyComplete();

r2dbc 写入成功log

这样就证明写成功了一条数据。

5.4 搭配 Webflux 使用

但是实际中该如何应用呢?目前能够想到的就是结合反应式框架Spring Webflux了,就像Spring Data JPA配合Spring MVC一样。

我们编写一个Webflux接口:

@RestController@RequestMapping("/user")public class ReactiveClientUserController {

    @Autowired    private ReactiveClientUserSortingRepository reactiveClientUserSortingRepository;

    /**     * 这里为了检验默认api 就不分层了     *     * @param userId the user id     * @return the mono     */    @GetMapping("/{userId}")    public Mono findUserById(@PathVariable String userId) {        return reactiveClientUserSortingRepository.findById(userId);    }

}

webflux 通过r2dbc查询mysql数据库

5.5 一些测试数据参考

在低并发时,Spring MVC + JDBC表现最佳,但在高并发下,WebFlux + R2DBC使用每个已处理请求的内存最少。

并发下的CPU占用

在高并发下,Spring MVC + JDBC的响应时间开始下降。显然,R2DBC在更高的并发性下提供了更好的响应时间。Spring WebFlux也比使用Spring MVC的类似实现更好。

吞吐量对比

6. 总结

今天对Spring Data R2DBC进一步演示,相信你能够从中学到一些东西。由于R2DBC还是比较新,还存在一些需要改进和补充的东西。目前社区非常活跃,发展十分迅速。好了今天的文章就到这里,原创不易多多关注:码农小胖哥  本文DEMO通过回复sdr 获取。如果你觉得本文很有用,请点赞、转发、再看。

往期推荐:

Spring Security 实战干货:401和403状态

2020-07-27

请不要再使用判断进行参数校验了

2020-07-25

Spring Security 实战干货:从零手写一个验证码登录

2020-07-22

mysql as用法_Spring Data R2DBC响应式操作MySQL相关推荐

  1. .NET 使用 MySql.Data.dll 动态库操作MySql的帮助类--MySqlHelper

    .NET 使用 MySql.Data.dll 动态库操作MySql的帮助类--MySqlHelper 參考演示样例代码,例如以下所看到的: /// <summary>/// MySql 数 ...

  2. VUE2中provide 和 inject用法,以及怎么做响应式数据?

    1. provide/inject说明 provide 和 inject, 用来实现实现跨组件之间通信. 父子/孙子组件之间任意通信. 在祖先组件中通过provide注入一个依赖,不论组件层次有多深, ...

  3. struct用法_精讲响应式webclient第1篇-响应式非阻塞IO与基础用法

    笔者在之前已经写了一系列的关于RestTemplate的文章,如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层HT ...

  4. mysql启动命令指定data目录_CentOS 7下MySQL的data目录更改后,使用mysqld服务启动失败...

    在CentOS 7系统下,通过rpm和yum命令安装MySQL,一般会采取service mysqld start命令来启动MySQL.在MySQL的配置文件/etc/my.cnf中,默认的data路 ...

  5. 数据库与身份认证(数据库的基本概念,安装并配置 MySQL,MySQL 的基本使用,在项目中操作 MySQL,前后端的身份认证)

    theme: channing-cyan 数据库与身份认证 1. 数据库的基本概念 1.1 什么是数据库 数据库(database)是用来组织.存储和管理数据的仓库. 当今世界是一个充满着数据的互联网 ...

  6. c 获取mysql列数据_转 用C API 操作MySQL数据库

    用C API 操作MySQL数据库 参考MYSQL的帮助文档整理 这里归纳了C API可使用的函数,并在下一节详细介绍了它们.请参见25.2.3节,"C API函数描述". 函数 ...

  7. php操作mysql数据库的扩展有哪些_8.PHP操作MySQL数据库(Mysqli扩展)

    思考:如果数据库的操作都是需要我们手动去调用客户端发送指令,那么这样的操作有什么意义呢? 引入:手动通过客户端操作MySQL数据库,只是我们学习SQL的一种手段.要实现数据库的自动调用,就需要客户端能 ...

  8. 怎么用php操作mysql删除数据库代码_如何使用php操作mysql的增删改查?

    php操作mysql的增删改查方法:1.插入语句[insert into 数据表名(字段1,字段2,....) values("值1","值2",..)]:2. ...

  9. golang mysql商业用例_完美起航-golang操作mysql用例

    golang操作mysql的demo,直接上代码 package main import ( "database/sql" "fmt" _ "gith ...

最新文章

  1. org.apache.hadoop.hdfs.server.datanode.DataNode: Exception in receiveBlock for block
  2. Error:Java home supplied via 'org.gradle.java.home' is invalid
  3. mysql查询去重第一条_Mysql用法记录 - Ashley-OSCHINA的个人空间 - OSCHINA - 中文开源技术交流社区...
  4. 石川es6课程---7、数组
  5. 6.494 - Kindergarten Counting Game
  6. 一些关于 SAP Spartacus 组件和模块延迟加载的问题和解答
  7. 老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)
  8. android view setleft,android – 在新textview上使用setLeft / setRight方法
  9. qpushbutton设置两个图标_宝马显示屏上的各种图标是啥意思,这里分享几个问的最多的!...
  10. mysql主从io为no_mysql主从同步错误解决和Slave_IO_Running: NO
  11. spring学习--引入外部文件,初始化属性
  12. matplotlib-plt.title
  13. Flask第十八篇 Flask-Migrate
  14. 【语音信号处理四】DTW算法
  15. 牛客网--16128--小名的回答
  16. Windows server 2012修改输入法
  17. 亲生骨肉 窥视父母遗产 为了继承遗产竟用这种方式替代...
  18. 爱快可以外接文件服务器吗,听说爱快路由器也支持NAS了?
  19. 高德地图功能点使用整理
  20. 世界上几乎没有技术驱动型公司

热门文章

  1. osg渲染到纹理技术(一)
  2. 关于bufferKnife8.8.1点击事件无效的原因
  3. ubuntu nginx php7,ubuntu 16 安装php7+nginx
  4. React Native发布重构路线图
  5. 机房收费系统——转换list泛型时,字段名称不正确应出现故障
  6. mysql 日期 时间戳 转换
  7. jsp调用servlet_宇宙最全Servlet详解!!
  8. python程序员脱单攻略_作为一只程序员,如何脱单?
  9. python画一个祝福别人生日快乐_分享快乐给朋友的生日快乐祝福语生日贺卡句子...
  10. php更新svn,利用php进行svn更新的php代码及php执行svn更新注意事项