Reactive Spring实战——响应式MySql交互

简介: 本文与大家探讨Spring中如何实现MySql响应式交互。Spring Data R2DBC项目是Spring提供的数据库响应式编程框架。 R2DBC是Reactive Relational Database Connectivity的首字母缩写词。 R2DBC是一个API规范倡议,它声明了一个响应式API,由驱动程序供应商实现,并以响应式编程的方式访问他们的关系数据库。 实现数据库的响应式编程并不容易,传统的JDBC协议是一个完全阻塞的 API,所以响应式编程对JDBC协议可以说是一种“颠覆”了。

本文与大家探讨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生成,多表查询等,这里不再一一介绍。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
4月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
808 3
|
7月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
2月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
2月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
7月前
|
人工智能 运维 Java
SpringBoot+MySQL实现动态定时任务
这是一个基于Spring Boot的动态定时任务Demo,利用spring-context模块实现任务调度功能。服务启动时会扫描数据库中的任务表,将任务添加到调度器中,并通过固定频率运行的ScheduleUpdater任务动态更新任务状态和Cron表达式。核心功能包括任务的新增、删除与Cron调整,支持通过ScheduledFuture对象控制任务执行。项目依赖Spring Boot 2.2.10.RELEASE,使用MySQL存储任务信息,包含任务基类ITask及具体实现(如FooTask),便于用户扩展运维界面以增强灵活性。
273 10
|
3月前
|
关系型数据库 MySQL PHP
PHP和Mysql前后端交互效果实现
本文介绍了使用PHP连接MySQL数据库的基本函数及其实现案例。内容涵盖数据库连接、选择数据库、执行查询、获取结果等常用操作,并通过用户登录和修改密码的功能实例,展示了PHP与MySQL的交互过程及代码实现。
320 0
PHP和Mysql前后端交互效果实现
|
7月前
|
人工智能 Java API
Spring AI 实战|Spring AI入门之DeepSeek调用
本文介绍了Spring AI框架如何帮助Java开发者轻松集成和使用大模型API。文章从Spring AI的初探开始,探讨了其核心能力及应用场景,包括手动与自动发起请求、流式响应实现打字机效果,以及兼容不同AI服务(如DeepSeek、通义千问)的方法。同时,还详细讲解了如何在生产环境中添加监控以优化性能和成本管理。通过Spring AI,开发者可以简化大模型调用流程,降低复杂度,为企业智能应用开发提供强大支持。最后,文章展望了Spring AI在未来AI时代的重要作用,鼓励开发者积极拥抱这一技术变革。
2718 71
Spring AI 实战|Spring AI入门之DeepSeek调用
|
4月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。

推荐镜像

更多