一、R2DBC

R2DBC(Reactive Relational Database Connectivity)是在 2018 年 Spring One Platform 大会被提出来的,它旨在使用完全无阻塞驱动程序创建数据库链接,为 SQL 数据库创建响应式 API。

Spring Data R2DBC项目是Spring Data家族的一部分,可轻松实现基于R2DBC的存储库。R2DBC(Reactive Relational Database Connectivity)是一个使用反应式驱动集成关系数据库的孵化器。Spring Data R2DBC运用熟悉的Spring抽象和repository 支持R2DBC。基于此,在响应式程序栈上使用关系数据访问技术,构建由Spring驱动的程序将变得非常简单。

目前,Spring Data R2DBC 支持 Postgres、H2、Microsoft SQL Server 、MySQL、MariaDB。

本篇文章基于 MySql ,做相关演示。

二、Spring Data R2DBC 使用

首先创建一个 SpringBoot 项目,确保 Spring Boot 的版本大于等于 2.3.0,在此版本之后才开始支持 MYSQL 的响应式驱动。

引入依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency><!--   连接池 -->
<dependency><groupId>io.r2dbc</groupId><artifactId>r2dbc-pool</artifactId>
</dependency><!--mysql 驱动-->
<dependency><groupId>dev.miku</groupId><artifactId>r2dbc-mysql</artifactId>
</dependency>

配置文件添加mysql的连接:

spring.r2dbc.name= r2dbc
spring.r2dbc.url= r2dbcs:mysql://127.0.0.1:3306/testdb?serverTimezone=GMT%2B8
spring.r2dbc.username=root
spring.r2dbc.password=root
spring.r2dbc.pool.enabled=true
spring.r2dbc.pool.validation-query= SELECT 1

引入上面的配置后,r2dbc 的环境就已经搭建完成了,使用 r2dbc 操作数据库,有多种方式,其中可以通过 ConnectionFactory 、DatabaseClient、R2dbcEntityTemplate、ReactiveCrudRepository,都可以进行数据库的操作。下面对这几种方式逐一进行介绍使用。

在操作之前,现在数据库中创建一张测试表,下面就针对该表进行操作:

CREATE TABLE `user` (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`phone` varchar(255) DEFAULT NULL,`mail` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

再创建一个实体类:

@Data
public class UserEntity {private Long id;private String name;private String phone;private String mail;
}

1. ConnectionFactory

在配置好上述环境后,直接就可以注入 ConnectionFactory 对象:

@Autowired
ConnectionFactory connectionFactory;

写入数据:

Mono.from(connectionFactory.create()).flatMap(connection -> Mono.from(connection.createStatement("INSERT INTO `testdb`.`user`(`name`, `phone`, `mail`) VALUES ( ?name, ?phone, ?mail)").bind("name", "张三").bind("phone", "111110").bind("mail", "111110@qq.com").returnGeneratedValues("id").execute()).map(result -> result.map((row, meta) -> row.get("id"))).flatMap(id -> Mono.from(id))).subscribe(id -> System.out.println("写入:" + id));



上面只是一个简单的写入,在项目中,有可能还有其他表的操作,或者其他业务逻辑,这种情况肯定需要事物,来保证数据的一致性了,下面对上面的操作加上事物:

在程序中故意加一个 int a = 1 / 0 来模拟异常:

Mono.from(connectionFactory.create()).flatMap(connection -> Mono.from(connection.beginTransaction()).then(Mono.from(connection.createStatement("INSERT INTO `testdb`.`user`(`name`, `phone`, `mail`) VALUES ( ?name, ?phone, ?mail)").bind("name", "张三").bind("phone", "111110").bind("mail", "111110@qq.com").returnGeneratedValues("id").execute())).map(result -> result.map((row, meta) -> row.get("id"))).flatMap(id -> Mono.from(id)).flatMap(id -> Mono.fromCallable(() -> {//其他业务逻辑System.out.println("写入的ID:" + id);int a = 1 / 0;return id;})).delayUntil(i -> connection.commitTransaction()).doOnError(e -> {System.out.println("异常回滚事物:" + e.getMessage());connection.rollbackTransaction();})).subscribe(id -> System.out.println("写入:" + id));



可以看到,ID为24的并没有写入数据库中。

下面将 int a = 1 / 0去除:


ID为26的也写入了数据库中。

查询数据

Mono.from(connectionFactory.create()).flatMap(connection -> Mono.from(connection.createStatement("SELECT id,name,phone,mail FROM user WHERE name = ?name").bind("name", "张三").execute())).flatMapMany(result -> Flux.from(result.map((row, meta) -> {UserEntity entity = new UserEntity();entity.setId(Long.parseLong(String.valueOf(row.get("id"))));entity.setName(String.valueOf(row.get("name")));entity.setPhone(String.valueOf(row.get("phone")));entity.setMail(String.valueOf(row.get("mail")));return entity;}))).subscribe(u -> System.out.println(u.toString()));

2. DatabaseClient

上面可以看到 ConnectionFactory 提供的 api 非常全,但使用起来有些麻烦,相比 DatabaseClient 就简单许多了。同样配置好环境后直接注入:

 @AutowiredDatabaseClient databaseClient;

修改下上面的实体类,加上几个注解,标识出表和字段:

@Data
@Table("user")
public class UserEntity {@Idprivate Long id;@Column("name")private String name;private String phone;private String mail;
}

执行SQL

databaseClient.execute("SELECT * FROM user").as(UserEntity.class).fetch().all().subscribe(System.out::println);


相比之下确实简化了许多吧,不过DatabaseClient还为常用操作提供了针对的方法,比如:

写入数据

UserEntity entity = new UserEntity();
entity.setName("王五");
entity.setPhone("11111");
entity.setMail("111@qq.com");databaseClient.insert().into(UserEntity.class).using(entity).fetch().all().subscribe(map -> System.out.println("写入ID:" + map.get("LAST_INSERT_ID")));

查询数据

databaseClient.select().from(UserEntity.class).matching(Criteria.where("name").is("李四").and(Criteria.where("phone").is("111110"))).orderBy(Sort.Order.desc("id")).fetch().all().subscribe(System.out::println);


更新数据

databaseClient.update().table("user").using(Update.update("name", "小王").set("phone", "110")).matching(Criteria.where("name").is("张三").and(Criteria.where("phone").is("111110"))).fetch().rowsUpdated().subscribe(i -> System.out.println("更新个数:" + i));


删除数据

databaseClient.delete().from("user").matching(Criteria.where("name").is("小王")).fetch().rowsUpdated().subscribe(i -> System.out.println("删除个数:" + i));

3. R2dbcEntityTemplate

R2dbcEntityTemplate 的使用方式和 DatabaseClient 差不多,但创建 R2dbcEntityTemplate 需要一个 DatabaseClient 对象:

@Configuration
public class R2dbcConfig {@Beanpublic R2dbcEntityTemplate r2dbcEntityTemplate(DatabaseClient databaseClient) {return new R2dbcEntityTemplate(databaseClient);}
}

写入数据

UserEntity entity = new UserEntity();
entity.setName("王五");
entity.setPhone("11111");
entity.setMail("111@qq.com");r2dbcEntityTemplate.insert(entity).subscribe(e-> System.out.println(e));


可以看出又比 DatabaseClient 简化了些。

查询数据

r2dbcEntityTemplate.select(Query.query(Criteria.where("name").is("李四").and(Criteria.where("phone").is("111110"))),UserEntity.class).subscribe(e-> System.out.println(e));


修改数据

r2dbcEntityTemplate.update(Query.query(Criteria.where("name").is("李四").and(Criteria.where("phone").is("111110"))),Update.update("name", "张三").set("phone", "22220"),UserEntity.class).subscribe(i -> System.out.println("更新数:" + i));


删除数据

r2dbcEntityTemplate.delete(Query.query(Criteria.where("name").is("张三").and(Criteria.where("phone").is("22220"))),UserEntity.class).subscribe(i -> System.out.println("删除数:" + i));

4. ReactiveCrudRepository

前面的使用都是基于提供的 api 进行调用,有使用过mybatis-plus,应该知道,经常用一个 BaseMapper类,帮我们实现了基本的操作,同时也可以在自己的Mapper 下,用 Mybatis 的注解进行操作,这里的ReactiveCrudRepository 也可以实现类似的功能。

新建一个 Dao ,实现 ReactiveCrudRepository

@Repository
public interface UserDao extends ReactiveCrudRepository<UserEntity, Long> {@Query("SELECT * FROM user WHERE id = :id")Flux<UserEntity> findDateById(Long id);@Query("UPDATE user SET name = :name WHERE id = :id")Mono<Integer> updateNameById(String name, Long id);
}

我们可以在其中 使用@Query执行特定的SQL,同时ReactiveCrudRepository提供给我们的有:

基本的操作都还是有的:

写入数据

 UserEntity entity = new UserEntity();entity.setName("王五");entity.setPhone("11111");entity.setMail("111@qq.com");userDao.save(entity).subscribe(e-> System.out.println(e));


使用自己的SQL查询

userDao.findDateById(36L).subscribe(e-> System.out.println(e));



喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!

Spring Data R2DBC 响应式数据库操作使用相关推荐

  1. mysql as用法_Spring Data R2DBC响应式操作MySQL

    1. 前言 在使用 R2DBC 操作 MySQL 数据库 一文中初步介绍了r2dbc-mysql的使用.但是借助于DatabaseClient操作MySQL,过于初级和底层,不利于开发.今天就利用Sp ...

  2. 【Spring 5】响应式Web框架实战(上)

    前情概要:  - [Spring 5]响应式Web框架前瞻  - 响应式编程总览 1 回顾 通过前两篇的介绍,相信你对响应式编程和Spring 5已经有了一个初步的了解.下面我将以一个简单的Sprin ...

  3. r2dbc_使用Spring Data R2DBC进行异步RDBMS访问

    r2dbc 不久之前,发布了JDBC驱动程序的React性变体. 称为R2DBC. 它允许将数据异步流传输到已预订的任何端点. 通过将R2DBC之类的React性驱动程序与Spring WebFlux ...

  4. 使用Spring Data R2DBC进行异步RDBMS访问

    不久之前,发布了JDBC驱动程序的反应型. 称为R2DBC. 它允许将数据异步流传输到已预订的任何端点. 通过将R2DBC之类的反应性驱动程序与Spring WebFlux结合使用,可以编写一个完整的 ...

  5. Spring系列学习之Spring Data R2DBC数据访问

    英文原文:https://spring.io/projects/spring-data-r2dbc 目录 概述 快速开始 学习 文档 示例 概述 Spring Data R2DBC是更大的Spring ...

  6. SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库

    微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 如题,今天介绍 Spring Data JPA 的使用. 什么是 Spring Data JPA 在介绍 Spri ...

  7. 【Spring 5】响应式Web框架实战(下)

    - [Spring 5]响应式Web框架前瞻  - 响应式编程总览  - [Spring 5]响应式Web框架实战(上) 1 回顾 上篇介绍了如何使用Spring MVC注解实现一个响应式Web应用( ...

  8. Kotlin 使用 Spring WebFlux 实现响应式编程

    Kotlin 使用 Spring WebFlux 实现响应式编程 IBM的研究称,整个人类文明所获得的全部数据中,有90%是过去两年内产生的.在此背景下,包括NoSQL,Hadoop, Spark, ...

  9. Spring BOOT ( 基于Kotlin 编程语言) 使用 Spring WebFlux 实现响应式编程

    Spring BOOT ( 基于Kotlin 编程语言) 使用 Spring WebFlux 实现响应式编程 image.png 参考文档:https://docs.spring.io/spring/ ...

  10. 06--MySQL自学教程:DML(Data Manipulation Language:数据库操作语言),只操作表

    1.DML(Data Manipulation Language:数据库操作语言) 1)DML(Data Manipulation Language:数据库操作语言): 只操作表(插入,删除,修改), ...

最新文章

  1. CircularFloatingActionMenu
  2. GridView 里的删除不起作用
  3. 使用css3进行增强
  4. Ionic+Angular实现中英国际化(附代码下载)
  5. 87-区间线段树(板子)--那个苑区的人最瘦
  6. Linux:9个实用shell运维脚本,值得收藏!
  7. for each循环_Power Query — 循环初步
  8. 正则表达式小括号的多义性
  9. DB2存储过程分页测试
  10. python动态演示数据gdp_荐爬取世界各国历年的GDP数据
  11. 信息系统项目管理师考试难吗
  12. 第一款在太空中使用的芯片
  13. 使用模块定义文件(.def)文件生成dll
  14. BUUCTF misc第二页WP
  15. Pycharm 一键加引号,快速加引号,批量加引号
  16. php版本kms,通过 AWS KMS API 和 AWS SDK for PHP 版本 3 使用别名 - 适用于 PHP 的 AWS 开发工具包...
  17. 软文营销是什么,怎么理解
  18. 【unity shader】unity游戏特效-仿《黑暗欺骗》模型消融消失效果
  19. 中科院90多科研人员集体辞职后续:已低调处理,被质疑所长新添重要职务
  20. JDK11 API 帮助文档下载【中文版】

热门文章

  1. 百度内容审查做敏感词库筛选
  2. Java集合框架总结
  3. python代码申请软件著作权_python自动化生成软件著作权的源代码
  4. 企业架构皇冠上的明珠:TOGAF
  5. Sequelize 大于_间接效应值大于1是正常的吗?Q群答疑20200405
  6. 【高级开发必掌握SQL】SQL优化篇
  7. 通达信快捷功能键大全
  8. 01-移植AZPR SoC到Xilinx Aritix7 FPGA
  9. python数据分析课程网盘-数据分析技能 全套 百度网盘 下载
  10. offer拿到手软,java分布式面试题及答案