当前位置: 首页 > news >正文

响应式编程库(三) -r2dbc

r2dbc整合

  • 什么是r2dbc
  • 版本选择
  • 简单试用
  • 整合springboot
    • DatabaseClient 进行查询
    • 使用Repository接口(对应mapper)
      • 实体类
      • 复杂查询(一对一)实体类转换器
      • 测试代码
      • 一对多关系

什么是r2dbc

反应式关系数据库连接(R2DBC)项目为关系数据库带来了反应式编程API。

基于Reactive Streams规范。R2DBC建立在Reactive Streams规范之上,它提供了一个完全反应式的非阻塞API

r2dbc 官网:https://r2dbc.io/
github: r2dbc-mysql 版本
spring-data r2dbc

版本选择

参考下表来确定适合你的项目的r2 dbc-mysql版本。

spring-boot-starter-data-r2dbcspring-data-r2dbcr2dbc-spir2dbc-mysql(recommended)
3.0.* and above3.0.* and above1.0.0.RELEASEio.asyncer:r2dbc-mysql:1.2.0
2.7.*1.5.*0.9.1.RELEASEio.asyncer:r2dbc-mysql:0.9.7
2.6.* and below1.4.* and below0.8.6.RELEASEdev.miku:r2dbc-mysql:0.8.2

简单试用

        <!-- https://mvnrepository.com/artifact/dev.miku/r2dbc-mysql --><dependency><groupId>dev.miku</groupId><artifactId>r2dbc-mysql</artifactId><version>0.8.2.RELEASE</version></dependency>
 @Testvoid connection() throws IOException {// r2dbc基于全异步、响应式、消息驱动// jdbc:mysql://localhost:3306/test// r2dbc:mysql://localhost:3306/test//0、MySQL配置MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration.builder().host("192.168.xx.xx").port(3306).username("root").password("123456").database("test").connectTimeout(Duration.ofSeconds(3)).build();//1、获取连接工厂MySqlConnectionFactory connectionFactory = MySqlConnectionFactory.from(configuration);//2、获取到连接,发送sqlMono<Connection> connectionMono = Mono.from(connectionFactory.create());// JDBC: Statement: 封装sql的//3、数据发布者connectionMono.flatMapMany(connection ->connection
//                                    .createStatement("INSERT INTO `t_book` (`publisher`, `author`) VALUES ('who', '1')").createStatement("select * from t_book where id=?id and publisher=?").bind("id", 1L) //具名参数.bind(1, "pub").execute()).flatMap(result -> {// 不同版本,api有所不一致return result.map((readable,book)->{System.out.println("readable:"+readable);System.out.println("book:"+book);Long id = readable.get("id", Long.class);String publisher = readable.get("publisher", String.class);Long author = readable.get("author", Long.class);return new TBook(author,publisher,id);});}).subscribe(tAuthor -> System.out.println("book = " + tAuthor));//背压; 不用返回所有东西,基于请求量返回;System.in.read();}

结果:

readable:dev.miku.r2dbc.mysql.MySqlRow@34579a88
book:MySqlRowMetadata{metadata=[MySqlColumnMetadata{index=0, type=8, name='id', definitions=4203, nullability=NON_NULL, size=20, decimals=0, collationId=63}, MySqlColumnMetadata{index=1, type=253, name='publisher', definitions=1001, nullability=NON_NULL, size=1020, decimals=0, collationId=45}, MySqlColumnMetadata{index=2, type=3, name='author_id', definitions=1001, nullability=NON_NULL, size=11, decimals=0, collationId=63}, MySqlColumnMetadata{index=3, type=12, name='create_time', definitions=81, nullability=NON_NULL, size=19, decimals=0, collationId=63}], sortedNames=[author_id, create_time, id, publisher]}
book = TBook(authorId=1, publisher=pub, id=1)

整合springboot

        <!-- https://mvnrepository.com/artifact/io.asyncer/r2dbc-mysql --><dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><version>1.0.5</version></dependency><!--        响应式 Spring Data R2dbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId></dependency>

DatabaseClient 进行查询

    @Autowired  //贴近底层,join操作好做; 复杂查询好用DatabaseClient databaseClient; //数据库客户端@Testvoid databaseClient() throws IOException {// 底层操作databaseClient.sql("select * from t_author")
//                .bind(0,2L).fetch() //抓取数据.all()//返回所有.map(map -> {  //map == bean  属性=值System.out.println("map = " + map);String id = map.get("id").toString();String name = map.get("name").toString();return new TAuthor(Long.parseLong(id), name, null);}).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}
spring:r2dbc:password: 123456username: rooturl: r2dbc:mysql://localhost:3306/testname: test

使用Repository接口(对应mapper)

/**
* TAuthor : 对应实体类;   Long  主键类型
*/
@Repository
public interface AuthorRepositories extends R2dbcRepository<TAuthor,Long> {//默认继承了一堆CRUD方法; 像mybatis-plus//QBC: Query By Criteria//QBE: Query By Example//成为一个起名工程师  where id In () and name like ?//仅限单表复杂条件查询。 不用编写sql!!!根据方法名自动生成sqlFlux<TAuthor> findAllByIdInAndNameLike(Collection<Long> id, String name);//多表复杂查询@Query("select * from t_author") //自定义query注解,指定sql语句Flux<TAuthor> findHaha();// 1-1关联关系; 查出这本图书以及它的作者@Query("select b.*,t.name as name from t_book b" +" LEFT JOIN t_author t on b.author_id = t.id " +" WHERE b.id = :bookId")Mono<TBookAuthor> authorBook(@Param("bookId") Long bookId);//    @Query("SELECT * FROM person WHERE lastname = :lastname")
//    Flux<Person> findByLastname(String lastname);
//
//    @Query("SELECT firstname, lastname FROM person WHERE lastname = $1")
//    Mono<Person> findFirstByLastname(String lastname);}

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor@Table("t_book")
public class TBook {Long authorId;String publisher;@IdLong id;}
@Table("t_author")
@NoArgsConstructor
@AllArgsConstructor
@Data
public class TAuthor {@Idprivate Long id;private String name;//1-N如何封装@Transient //临时字段,并不是数据库表中的一个字段
//    @Field(exist=false)private List<TBook> TBooks;
}

@Table("t_book")
@Data
public class TBookAuthor {@IdLong id;Long authorId;String publisher;/*** 响应式中日期的映射用 Instant 或者 LocalXxx*/Instant createTime;/*** 一对一 关系 实体类*/TAuthor TAuthor;}

复杂查询(一对一)实体类转换器

springdata r2dbc mapping 文档


/*** 告诉Spring Data 怎么封装 TBookAuthor 对象*/
@ReadingConverter
public class BookAuthorConverter implements Converter<Row, TBookAuthor> {//1)、@Query 指定了 sql如何发送//2)、自定义 BookConverter 指定了 数据库返回的一 Row 数据,怎么封装成 TBook//3)、配置 R2dbcCustomConversions 组件,让 BookConverter 加入其中生效@Overridepublic TBookAuthor convert(Row source) {if(source == null) return null;//自定义结果集的封装TBookAuthor tBook = new TBookAuthor();tBook.setId(source.get("id", Long.class));tBook.setPublisher(source.get("publisher", String.class));Long author_id = source.get("author_id", Long.class);tBook.setAuthorId(author_id);tBook.setCreateTime(source.get("create_time", Instant.class));//让 converter兼容更多的表结构处理
//        if (source.get("name",String.class)) {TAuthor tAuthor = new TAuthor();tAuthor.setId(author_id);tAuthor.setName(source.get("name", String.class));tBook.setTAuthor(tAuthor);
//        }return tBook;}
}

注册转换器


@EnableR2dbcRepositories //开启 R2dbc 仓库功能;jpa
@Configuration
public class R2DbcConfiguration {@Bean //替换容器中原来的@ConditionalOnMissingBeanpublic R2dbcCustomConversions conversions(){//把我们的转换器加入进去; 效果新增了我们的 Converterreturn R2dbcCustomConversions.of(MySqlDialect.INSTANCE,new BookAuthorConverter());}
}

测试代码

@SpringBootTest
public class AppTest {@AutowiredTBookMapper bookMapper;@Testvoid testCRUD() throws IOException {
//         bookMapper.findAll().subscribe(System.out::println);
//        bookMapper.findById(1L).subscribe(System.out::println);TBookAuthor block = bookMapper.authorBook(1L).block();System.out.println(block);//查询是全异步的, 需要阻塞一下System.in.read();}}

一对多关系

在这里插入图片描述

    @Testvoid oneToN() throws IOException {//        databaseClient.sql("select a.id aid,a.name,b.* from t_author a  " +
//                "left join t_book b on a.id = b.author_id " +
//                "order by a.id")
//                .fetch()
//                .all(row -> {
//
//                })// 1~6// 1:false 2:false 3:false 4: true 8:true 5:false 6:false 7:false 8:true 9:false 10:false// [1,2,3]// [4,8]// [5,6,7]// [8]// [9,10]// bufferUntilChanged:// 如果下一个判定值比起上一个发生了变化就开一个新buffer保存,如果没有变化就保存到原buffer中//        Flux.just(1,2,3,4,8,5,6,7,8,9,10)
//                .bufferUntilChanged(integer -> integer%4==0 )
//                .subscribe(list-> System.out.println("list = " + list));; //自带分组Flux<TAuthor> flux = databaseClient.sql("select a.id aid,a.name,b.* from t_author a  " +"left join t_book b on a.id = b.author_id " +"order by a.id").fetch().all().bufferUntilChanged(rowMap -> Long.parseLong(rowMap.get("aid").toString())).map(list -> {TAuthor tAuthor = new TAuthor();Map<String, Object> map = list.get(0);tAuthor.setId(Long.parseLong(map.get("aid").toString()));tAuthor.setName(map.get("name").toString());//查到的所有图书List<TBook> tBooks = list.stream().map(ele -> {TBook tBook = new TBook();tBook.setId(Long.parseLong(ele.get("id").toString()));tBook.setAuthorId(Long.parseLong(ele.get("author_id").toString()));tBook.setTitle(ele.get("title").toString());return tBook;}).collect(Collectors.toList());tAuthor.setBooks(tBooks);return tAuthor;});//Long 数字缓存 -127 - 127;// 对象比较需要自己写好equals方法flux.subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}

相关文章:

响应式编程库(三) -r2dbc

r2dbc整合 什么是r2dbc版本选择简单试用整合springbootDatabaseClient 进行查询使用Repository接口(对应mapper)实体类复杂查询&#xff08;一对一&#xff09;实体类转换器测试代码一对多关系 什么是r2dbc 反应式关系数据库连接&#xff08;R2DBC&#xff09;项目为关系数据库…...

嵌入式AI革命:DeepSeek开源如何终结GPU霸权,开启单片机智能新时代?

2025年&#xff0c;全球AI领域最震撼的突破并非来自算力堆叠的超级模型&#xff0c;而是中国团队DeepSeek通过开源策略&#xff0c;推动大模型向微型化、低功耗场景的跨越。相对于当人们还在讨论千亿参数模型的训练成本被压缩到600万美金而言&#xff0c;被称作“核弹级别”的操…...

基于遗传算法的64QAM星座图的最优概率整形matlab仿真,对比优化前后整形星座图和误码率

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; GA优化过程&#xff1a; 优化前后星座图对比&#xff1a; &#xff08;优化后…...

从零开始玩转Docker:轻松开启容器化之旅

一、什么是 Docker Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。简单来说&#xff0c;Docker 就像是一个超级 “快递箱”&#xff0c…...

kafka生产端之架构及工作原理

文章目录 整体架构元数据更新 整体架构 消息在真正发往Kafka之前&#xff0c;有可能需要经历拦截器&#xff08;Interceptor&#xff09;、序列化器&#xff08;Serializer&#xff09;和分区器&#xff08;Partitioner&#xff09;等一系列的作用&#xff0c;那么在此之后又会…...

38、【OS】【Nuttx】OSTest分析(3):参数传递

背景 接之前 blog 36、【OS】【Nuttx】OSTest分析&#xff08;2&#xff09;&#xff1a;环境变量测试 37、【OS】【Nuttx】OSTest分析&#xff08;2&#xff09;&#xff1a;任务创建 分析完环境变量测试&#xff0c;和任务创建的一些关键要素&#xff0c;OSTest 进入下一阶段…...

存储异常导致的Oracle重大生产故障

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…...

C语言时间相关宏定义

在C语言中&#xff0c;预处理器提供了一些与时间相关的宏定义&#xff0c;用于在编译时获取日期、时间等信息。除了 __TIMESTAMP__ 和 __DATE__&#xff0c;还有以下相关的宏定义&#xff1a; __DATE__ 当前编译日期的字符串&#xff0c;格式为 "Mmm dd yyyy"&#x…...

Android Studio:Application 和 Activity的区别

Application 和 Activity 是 Android 中非常重要的两个组件&#xff0c;它们分别负责不同的生命周期管理和应用的不同层次的操作。 Application 是应用级别的生命周期管理&#xff0c;它在整个应用运行时只有一个实例&#xff0c;负责应用的全局初始化和资源管理。Activity 是…...

如何优化爬虫以提高搜索效率

在数据采集和网络爬虫领域&#xff0c;优化爬虫性能是提升数据采集效率的关键。随着网页结构的日益复杂和数据量的不断增长&#xff0c;高效的爬虫能够显著降低运行时间和资源成本。本文将详细介绍如何优化爬虫以提高搜索效率&#xff0c;包括选择合适的工具、优化代码逻辑、使…...

git撤销上一次的提交

1、撤销提交 如果需要撤销上一次的提交&#xff0c;只是提交到了本地&#xff0c;可以通过命令&#xff1a; // 撤销最近的提交&#xff08;保留修改&#xff09; git reset --soft HEAD~1 这个操作可以保留之前的提交和当前的修改。最近一次的提交到本地的修改的提交会回到…...

LLM学习笔记1——本地部署Meta-Llama-3.2-1B大模型

系列文章目录 参考博客 参考博客 文章目录 系列文章目录前言与调用一、部署要求二、实现步骤0.深度学习环境错误1&#xff0c;验证pytorch版本时提示以下问题&#xff1a;错误2&#xff0c;验证pytorch版本时提示以下问题&#xff1a;错误3&#xff0c;有时候还会提示你有一些…...

Nginx反代Ollama接口跨域、无法逐字输出问题

场景 本地部署deepseek模型&#xff0c;用的Ollama管理&#xff0c;内网穿透到公网&#xff0c;在通过nginx反代ollama接口。 问题描述 跨域问题 nginx转发时请求头中需要加入origin&#xff0c;并且origin还要和ollama接口同源&#xff08;协议、ip、端口一致&#xff09;。…...

大学资产管理系统中的下载功能设计与实现

大学资产管理系统是高校信息化建设的重要组成部分&#xff0c;它负责记录和管理学校内所有固定资产的信息。随着信息技术的发展&#xff0c;下载功能成为提高资产管理效率的关键环节之一。 系统架构的设计是实现下载功能的基础。一个良好的系统架构能够确保数据的高效传输和存储…...

股指入门:股指期货是什么意思?在哪里可以做股指期货交易?

股指期货是一种以股票指数为标的物的期货合约&#xff0c;也可以称为股票指数期货或期指。 股指期货是什么意思&#xff1f; 股指期货是一种金融衍生品&#xff0c;其标的资产是股票市场上的股指&#xff0c;例如标普500指数、道琼斯工业平均指数、上证50指数等。 股指期货允…...

< OS 有关 > 利用 google-drive-ocamlfuse 工具,在 Ubuntu 24 系统上 加载 Google DRIVE 网盘

Created by Dave On 8Feb.2025 起因&#xff1a; 想下载 StableDiffusion&#xff0c;清理系统文件时把 i/o 搞到 100%&#xff0c;已经删除到 apt 缓存&#xff0c;还差 89MB&#xff0c;只能另想办法。 在网上找能不能挂在 Google 网盘&#xff0c;百度网盘&#xff0c;或 …...

Golang的引用类型和指针

在Golang中&#xff0c;引用类型和指针是两个容易混淆的概念&#xff0c;但它们有本质的区别。理解它们的区别对于编写高效、正确的Go代码至关重要。 1. 引用类型 引用类型是Go语言中某些内置类型的统称&#xff0c;它们的值在传递时共享底层数据&#xff0c;而不是复制数据。…...

51单片机之冯·诺依曼结构

一、概述 8051系列单片机将作为控制应用最基本的内容集成在一个硅片上&#xff0c;其内部结构如图4-1所示。作为单一芯片的计算机&#xff0c;它的内部结构与一台计算机的主机非常相似。其中微处理器相当于计算机中的CPU&#xff0c;由运算器和控制器两个部分构成&#xff1b;…...

32. C 语言 安全函数( _s 尾缀)

本章目录 前言什么是安全函数&#xff1f;安全函数的特点主要的安全函数1. 字符串操作安全函数2. 格式化输出安全函数3. 内存操作安全函数4. 其他常用安全函数 安全函数实例示例 1&#xff1a;strcpy_s 和 strcat_s示例 2&#xff1a;memcpy_s示例 3&#xff1a;strtok_s 总结 …...

Android T(13) 源码分析 — BufferQueue 的分析

Android T(13) 源码分析 — BufferQueue 的分析 文章目录 Android T(13) 源码分析 — BufferQueue 的分析前言摘要一、Java 层的 BufferQueue 分析二、原生层的 BufferQueue 分析1、BLASTBufferQueue 的创建2、BLASTBufferQueue 的更新3、Surface 的创建 总结 前言 该系列文章…...

Hotkey Detective:Windows热键冲突终极诊断指南

Hotkey Detective&#xff1a;Windows热键冲突终极诊断指南 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你是否曾经遇到…...

ESXi 重置密码详细攻略(全场景覆盖)

本文详细覆盖 ESXi 所有常见场景的密码重置方法&#xff0c;包括「知道原密码改新密码」「忘记root密码(无vCenter)」「有vCenter管理(企业版)」&#xff0c;步骤拆解到每一步点击和命令输入&#xff0c;适配 ESXi 5.x/6.x/7.x/8.x 全版本&#xff0c;兼顾官方支持方法和实用非…...

多品种小批量时代的排产革命:JVS-APS智能排产突破交付周期瓶颈

"紧急订单插入&#xff0c;全产线排程推倒重来"、"设备冲突、物料短缺让排产计划沦为纸上谈兵"、"明明产能充足&#xff0c;订单交付周期却比同行长30%"——这些困境正在困扰着越来越多的制造企业。在现代制造业中&#xff0c;多品种小批量生产模…...

跨平台部署YOLOv5的路径陷阱:从WindowsPath错误看Python pathlib的兼容性设计

1. 当WindowsPath遇上Linux&#xff1a;YOLOv5部署的路径陷阱 最近帮朋友调试一个YOLOv5模型部署问题&#xff0c;场景特别典型&#xff1a;在Windows训练好的目标检测模型&#xff0c;迁移到Linux服务器就报错。错误信息直指一个看似简单的路径问题&#xff1a;"NotImple…...

量子密钥分发系统的工程实践(四):基于FPGA的后处理核心模块剖析

1. FPGA在QKD后处理中的核心作用 量子密钥分发&#xff08;QKD&#xff09;系统的后处理环节就像一位严谨的会计&#xff0c;需要把原始账本&#xff08;量子信号&#xff09;整理成无可争议的最终报表&#xff08;安全密钥&#xff09;。而FPGA在这个过程中的角色&#xff0c;…...

从特效 SDK 到 AI 动效平台:Neon Vibe Motion 的技术演进之路

多媒体中台在 B 站主要负责剪辑、拍摄、直播等业务场景的动效渲染&#xff0c;开发维护的 SDK 在后文统一称为特效 SDK。 传统的视频特效生产一般分三条链路&#xff1a; 三条链路存在一个困境&#xff1a;效果丰富度、实时可交互、生产效率&#xff0c;三者不可兼得。 那么能…...

手把手教你用PyTorch 2.0复现风源AI气象模型(附GitHub源码解读)

手把手教你用PyTorch 2.0复现风源AI气象模型&#xff08;附GitHub源码解读&#xff09; 气象预测正经历从传统数值模拟到AI驱动的范式转移。本文将带您深入风源模型的技术内核——一个融合卫星遥感与深度学习的混合架构&#xff0c;通过PyTorch 2.0实现从数据预处理到模型推理的…...

开箱即用!Qwen-Image-2512-SDNQ Web服务快速体验指南

开箱即用&#xff01;Qwen-Image-2512-SDNQ Web服务快速体验指南 1. 五分钟了解Qwen-Image-2512-SDNQ Web服务 你是否遇到过这样的场景&#xff1a;需要快速生成一张概念图&#xff0c;但打开专业设计软件太麻烦&#xff1f;或者想尝试AI绘画&#xff0c;却被复杂的模型部署步…...

【独家首发】基于eBPF+Java Agent+Istio Telemetry V2的零侵入式调试框架(已落地金融级生产环境,QPS>50K场景验证)

第一章&#xff1a;零侵入式调试框架的演进逻辑与金融级落地价值传统调试方式依赖代码埋点、日志增强或代理注入&#xff0c;不仅增加系统耦合度&#xff0c;更在高敏感、强一致性的金融核心系统中引入不可控风险。零侵入式调试框架应运而生——它不修改业务字节码、不依赖特定…...

Element Plus访问优化指南:从卡顿到流畅的开发体验提升方案

Element Plus访问优化指南&#xff1a;从卡顿到流畅的开发体验提升方案 【免费下载链接】element-plus &#x1f389; A Vue.js 3 UI Library made by Element team 项目地址: https://gitcode.com/GitHub_Trending/el/element-plus 在前端开发过程中&#xff0c;你是否…...