本文与大家探讨Spring中如何实现MySql响应式交互。

Spring Data R2DBC项目是Spring提供的数据库响应式编程框架。

R2DBC是Reactive Relational Database Connectivity的首字母缩写词。 R2DBC是一个API规范倡议,它声明了一个响应式API,由驱动程序供应商实现,并以响应式编程的方式访问他们的关系数据库。

实现数据库的响应式编程并不是容易的,传统的JDBC协议是一个完全阻塞的 API,所以响应式编程对JDBC协议可以说是一种“颠覆”了。

这里再强调一次响应式编程,响应式编程是一种非阻塞异步的编程模式,而Spring响应式编程提供了一种友好、直观、易于理解的编码模式处理异步结果(可参考前面的文章)。

也就是说,应用发送SQL给数据库后,应用线程不需要阻塞等待数据库返回结果,而是直接返回处理其他任务,等到数据库SQL处理完成后,再由Spring调用线程处理结果。

到目前,Spring Data R2DBC项目支持以下数据库:

H2 (io.r2dbc:r2dbc-h2)

MariaDB (org.mariadb:r2dbc-mariadb)

Microsoft SQL Server (io.r2dbc:r2dbc-mssql)

MySQL (dev.miku:r2dbc-mysql)

jasync-sql MySQL (com.github.jasync-sql:jasync-r2dbc-mysql)

Postgres (io.r2dbc:r2dbc-postgresql)

Oracle (com.oracle.database.r2dbc:oracle-r2dbc)

下面基于MySql,介绍一下Spring Data R2DBC使用方式。

引入依赖

    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency> <dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
<version>0.8.2.RELEASE</version>
</dependency>

配置文件

spring.r2dbc.url=r2dbcs:mysql://127.0.0.1:3306/bin-springreactive?useSSL=false
spring.r2dbc.username=...
spring.r2dbc.password=...

Spring Data R2DBC可以与Spring Data JPA结合使用,其实R2DBC与原来的JPA使用方式差别不大,使用非常简单。

只是Spring Data JPA中方法返回的是真实的值,而R2DBC中,返回的是数据流Mono,Flux。

简单介绍一个Spring Data JPA。Spring Data JPA是Spring基于ORM框架、JPA规范的基础上封装的一套 JPA (Java Persistence API) 应用框架,简单说,就是类似Mybatis,Hibernate的框架(Spring Data JPA底层通过Hibernate操作数据库)。

Repository是Spring Data R2DBC中的重要概念,封装了对一个实体的操作,相当于一个dao(Data Access Object,数据访问对象)。

假如应用中有一个实体DeliveryCompany,对应表delivery_company。

实体定义如下:

public class DeliveryCompany {
@Id
private long id;
private String name;
private String label;
private Integer level;
...
}

@Id注解标志了id属性。

下面我们定义一个DeliveryCompanyRepository接口,继承与R2dbcRepository。

@Repository
public interface DeliveryCompanyRepository extends R2dbcRepository<DeliveryCompany,Long> {
...
}

R2dbcRepository是Spring实现的接口,该接口继承与ReactiveCrudRepository,ReactiveCrudRepository接口提供了增删改查的模板方法。

public interface ReactiveCrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> Mono<S> save(S var1); <S extends T> Flux<S> saveAll(Iterable<S> var1); <S extends T> Flux<S> saveAll(Publisher<S> var1); Mono<T> findById(ID var1); Mono<T> findById(Publisher<ID> var1); ...
}

注意这里的返回结果,是Mono、Flux等异步结果,这就是响应式交互与非响应式交互的最大区别。

如果要自定义操作,有以下方式

(1) 通过方法名定义

只要我们按规则定义方法名,Spring就会为我们生成SQL。

// 按名称查找
Flux<DeliveryCompany> findByName(String name); // 查找给定范围内的
Flux<DeliveryCompany> findByIdGreaterThan(Long startId); // 查找大于给定id的数据
Flux<DeliveryCompany> findByIdGreaterThan(Long startId); // 查询名称以给定字符串开头的数据
Flux<DeliveryCompany> findByNameStartingWith(String start); // 分页
Flux<DeliveryCompany> findByIdGreaterThanEqual(Long startId, Pageable pageable);

注意,上面方法名需要按规范定义

findByName -> findBy<fieldName>
findByIdGreaterThan -> findBy<fieldName>GreaterThan

Spring会为我们生成对应的SQL,非常方便。这种方法可以满足多数简单的查询。

对应的还有删除操作

Mono<Integer> deleteByName(String name);

详细的方法命名规则,则参考官方文档。

(2)手动编写SQL

对于复杂的SQL,开发人员也可以手写SQL,

@Query("select  id,name from delivery_company where id in  (:ids)")
Flux<DeliveryCompany> findByIds2(List<Long> ids); @Query("select id,name from delivery_company where name = :name")
Flux<DeliveryCompany> findByName2(String name); @Modifying
@Query("update delivery_company set name = :name where id = :id")
Mono<DeliveryCompany> update2(@Param("id") long id, @Param("name") String name);

可以看到,编写SQL也非常简单,对于集合参数支持非常好。

目前未发现使用JPQL(Java Persistence Query Language)的方式,不过使用原生的SQL是没有问题的。

如果大家使用过Mybatis,应该会用过以下判断参数非空的做法

<select id="findByName2"
resultType="DeliveryCompany">
SELECT * FROM delivery_company
WHERE name = #{name}
<if test="label != null">
AND label like #{label}
</if>
</select>

可惜在JPA中非找到支持的方法,如果有同学知道,请不吝指教。

(3) 使用R2dbcEntityTemplate

另外,可以使用R2dbcEntityTemplate自动生成SQL

    @Autowired
private R2dbcEntityTemplate template; public Flux<DeliveryCompany> getByName3(String name) {
return template
.select(DeliveryCompany.class)
.from("delivery_company")
.matching(Query.query(Criteria.where("name").is(name))).all();
// Criteria.where("name").is(name).and
} public Mono<Integer> update3(DeliveryCompany company) {
return template
.update(DeliveryCompany.class)
.inTable("delivery_company")
.matching(Query.query(Criteria.where("id").is(company.getId())))
.apply(Update.update("name", company.getName()));
}

这种方式可以实现判断参数非空查询,不过使用起来较为繁琐(我们也可以对其进行一定的封装以方便我们使用)。

(4)Spring Data R2DBC中同样支持Querydsl,

我们定义的Repository可以继承于ReactiveQuerydslPredicateExecutor,该接口提供以下模板方法

public interface ReactiveQuerydslPredicateExecutor<T> {
Mono<T> findOne(Predicate var1); Flux<T> findAll(Predicate var1); Flux<T> findAll(Predicate var1, Sort var2); Flux<T> findAll(Predicate var1, OrderSpecifier... var2); Flux<T> findAll(OrderSpecifier... var1); Mono<Long> count(Predicate var1); Mono<Boolean> exists(Predicate var1);
}

Spring Data R2DBC中同样支持@QuerydslPredicate注解,这里不再深入。

Spring Data R2DBC支持事务,使用方法很简单,在业务方法添加@Transactional即可

    @Transactional
public Flux<DeliveryCompany> save(List<DeliveryCompany> companyList) {
Flux<DeliveryCompany> result = Flux.just();
for (DeliveryCompany deliveryCompany : companyList) {
result = result.concat(result, repository.save(deliveryCompany));
}
return result;
}

为了展示事务的使用,这里没有调用Repository的saveAll方法,而是循环插入数据并返回最后的结果。

注意,最后的结果Flux、Mono一定要作为方法返回值,因为响应式编程的异常信息保存在这些结果中(而不是在方法调用时抛出),所以这些结果必须作为方法返回值,否则Spring无法知道方法是否报错,也就无法回退事务。

Spring Data R2DBC基本与Spring Data JPA的使用相同,所以本篇文章主要还是对Spring Data JPA使用方式的介绍。

我之前并没有使用过Spring Data JPA,本篇文章主要还是入门介绍,还有很多东西没有涉及,如id生成,多表查询等,这里不再一一介绍。

官方文档:https://docs.spring.io/spring-data/r2dbc/docs/1.3.2/reference/html/

文章完整代码:https://gitee.com/binecy/bin-springreactive/tree/master/delivery-service

如果您觉得本文不错,欢迎关注我的微信公众号,系列文章持续更新中。您的关注是我坚持的动力!

Reactive Spring实战 -- 响应式MySql交互的更多相关文章

  1. Reactive Spring实战 -- 响应式Redis交互

    本文分享Spring中如何实现Redis响应式交互模式. 本文将模拟一个用户服务,并使用Redis作为数据存储服务器. 本文涉及两个java bean,用户与权益 public class User ...

  2. Reactive Spring实战 -- 响应式Kafka交互

    本文分享如何使用KRaft部署Kafka集群,以及Spring中如何实现Kafka响应式交互. KRaft 我们知道,Kafka使用Zookeeper负责为kafka存储broker,Consumer ...

  3. Reactive 理解 SpringBoot 响应式的核心-Reactor

    Reactive 理解 SpringBoot 响应式的核心-Reactor bestcoding 2020-02-23 17:26:43 一.前言 关于 响应式 Reactive,前面的两篇文章谈了不 ...

  4. 第二百五十一节,Bootstrap项目实战--响应式轮播图

    Bootstrap项目实战--响应式轮播图 学习要点: 1.响应式轮播图 本节课我们要在导航条的下方做一张轮播图,自动播放最新的重要动态. 一.响应式轮播图 响应式轮播图 第一步,设置轮播器区域car ...

  5. 第二百五十节,Bootstrap项目实战--响应式导航

    Bootstrap项目实战--响应式导航 学习要点: 1.响应式导航 一.响应式导航 基本导航组件+响应式 第一步,声明导航区域,设置导航默认样式,设置导航条固定在顶部navbar样式class类,写 ...

  6. Java9第四篇-Reactive Stream API响应式编程

    我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...

  7. Spring 5 响应式编程

    要点 Reactor 是一个运行在 Java8 之上的响应式流框架,它提供了一组响应式风格的 API 除了个别 API 上的区别,它的原理跟 RxJava 很相似 它是第四代响应式框架,支持操作融合, ...

  8. Reactive(1) 从响应式编程到"好莱坞"

    目录 概念 面向流设计 异步化 响应式宣言 参考文档 概念 Reactive Programming(响应式编程)已经不是一个新东西了. 关于 Reactive 其实是一个泛化的概念,由于很抽象,一些 ...

  9. Reactive Spring实战 -- WebFlux使用教程

    WebFlux是Spring 5提供的响应式Web应用框架. 它是完全非阻塞的,可以在Netty,Undertow和Servlet 3.1+等非阻塞服务器上运行. 本文主要介绍WebFlux的使用. ...

随机推荐

  1. C语言程序设计#成绩查询系统

    学生成绩管理系统 [注释]:请点赞,好人一生平[yi]安[wo]. #codeblocks程序下编写 #include<stdio.h>#include<stdlib.h>// ...

  2. power delivery功率输出

    delivery

  3. unity 使用OnDrag实现物体旋转

    通过监听UGUI的OnDrag事件 实现对3D物体的旋转 实现IDragHandler接口 void IDragHandler.OnDrag(PointerEventData eventData) { ...

  4. .NET平台系列16 .NET5/Asp.Net Core 在全球Web框架权威性能测试 Web Framework Benchmarks 中的吊炸天表现

    系列目录     [已更新最新开发文章,点击查看详细] TechEmpower Web Framework Benchmarks 是许多Web应用程序框架执行基本任务(如JSON序列化.数据库访问和服 ...

  5. Paddle概述

    Paddle概述 本文结合深度学习理论与实践,使用百度飞桨平台实现自然语言处理.计算机视觉及个性化推荐等领域的经典应用. 实践部分使用飞桨深度学习开源框架,适配最新的2.0版本,默认使用动态图编程范式 ...

  6. 算法编程Algos Programming

    算法编程Algos Programming 不同算法的集合,用于编程比赛,如ACM ICPC. 算法按主题划分.大多数算法都可以从文件中按原样运行.每种算法都有一个参考问题,并对其时间和空间复杂度作了 ...

  7. httprunner的简介、httprunner做接口测试入门知识,使用httprunner模拟get请求及post请求

    一.httprunner的简介 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种 ...

  8. Git_远程仓库fork操作

    fork操作:当选择 fork,相当于自己有了一份原项目的拷贝,当然这个拷贝只是针对当时的项目文件,如果后续原项目文件发生改变,你必须通过其他的方式去同步. 使用场景:一般来说,不需要使用 fork ...

  9. postgresql无序uuid性能测试

    无序uuid对数据库的影响 由于最近在做超大表的性能测试,在该过程中发现了无序uuid做主键对表插入性能有一定影响.结合实际情况发现当表的数据量越大,对表插入性能的影响也就越大. 测试环境 Postg ...

  10. 【NX二次开发】大开眼界,DLL还可以这么调!

    NX二次开发应用程序有交互式.批处理和远程3中模式.交互模式的应用程序(.dll)在NX界面环境下运行.dll以动态链接库的方式被加载到NX的进程空间中.dll可以通过下列几种方式执行. 1.直接激活 ...