Spring Data R2DBC 响应式数据库操作使用
一、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 响应式数据库操作使用相关推荐
- mysql as用法_Spring Data R2DBC响应式操作MySQL
1. 前言 在使用 R2DBC 操作 MySQL 数据库 一文中初步介绍了r2dbc-mysql的使用.但是借助于DatabaseClient操作MySQL,过于初级和底层,不利于开发.今天就利用Sp ...
- 【Spring 5】响应式Web框架实战(上)
前情概要: - [Spring 5]响应式Web框架前瞻 - 响应式编程总览 1 回顾 通过前两篇的介绍,相信你对响应式编程和Spring 5已经有了一个初步的了解.下面我将以一个简单的Sprin ...
- r2dbc_使用Spring Data R2DBC进行异步RDBMS访问
r2dbc 不久之前,发布了JDBC驱动程序的React性变体. 称为R2DBC. 它允许将数据异步流传输到已预订的任何端点. 通过将R2DBC之类的React性驱动程序与Spring WebFlux ...
- 使用Spring Data R2DBC进行异步RDBMS访问
不久之前,发布了JDBC驱动程序的反应型. 称为R2DBC. 它允许将数据异步流传输到已预订的任何端点. 通过将R2DBC之类的反应性驱动程序与Spring WebFlux结合使用,可以编写一个完整的 ...
- Spring系列学习之Spring Data R2DBC数据访问
英文原文:https://spring.io/projects/spring-data-r2dbc 目录 概述 快速开始 学习 文档 示例 概述 Spring Data R2DBC是更大的Spring ...
- SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库
微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 如题,今天介绍 Spring Data JPA 的使用. 什么是 Spring Data JPA 在介绍 Spri ...
- 【Spring 5】响应式Web框架实战(下)
- [Spring 5]响应式Web框架前瞻 - 响应式编程总览 - [Spring 5]响应式Web框架实战(上) 1 回顾 上篇介绍了如何使用Spring MVC注解实现一个响应式Web应用( ...
- Kotlin 使用 Spring WebFlux 实现响应式编程
Kotlin 使用 Spring WebFlux 实现响应式编程 IBM的研究称,整个人类文明所获得的全部数据中,有90%是过去两年内产生的.在此背景下,包括NoSQL,Hadoop, Spark, ...
- Spring BOOT ( 基于Kotlin 编程语言) 使用 Spring WebFlux 实现响应式编程
Spring BOOT ( 基于Kotlin 编程语言) 使用 Spring WebFlux 实现响应式编程 image.png 参考文档:https://docs.spring.io/spring/ ...
- 06--MySQL自学教程:DML(Data Manipulation Language:数据库操作语言),只操作表
1.DML(Data Manipulation Language:数据库操作语言) 1)DML(Data Manipulation Language:数据库操作语言): 只操作表(插入,删除,修改), ...
最新文章
- CircularFloatingActionMenu
- GridView 里的删除不起作用
- 使用css3进行增强
- Ionic+Angular实现中英国际化(附代码下载)
- 87-区间线段树(板子)--那个苑区的人最瘦
- Linux:9个实用shell运维脚本,值得收藏!
- for each循环_Power Query — 循环初步
- 正则表达式小括号的多义性
- DB2存储过程分页测试
- python动态演示数据gdp_荐爬取世界各国历年的GDP数据
- 信息系统项目管理师考试难吗
- 第一款在太空中使用的芯片
- 使用模块定义文件(.def)文件生成dll
- BUUCTF misc第二页WP
- Pycharm 一键加引号,快速加引号,批量加引号
- php版本kms,通过 AWS KMS API 和 AWS SDK for PHP 版本 3 使用别名 - 适用于 PHP 的 AWS 开发工具包...
- 软文营销是什么,怎么理解
- 【unity shader】unity游戏特效-仿《黑暗欺骗》模型消融消失效果
- 中科院90多科研人员集体辞职后续:已低调处理,被质疑所长新添重要职务
- JDK11 API 帮助文档下载【中文版】