R2DBC-响应式数据库

news2025/1/16 2:39:16

简单查询

基于全异步,响应式,消息驱动
用法:
1.导入驱动:导入连接池(r2dbc-pool),导入驱动(r2dbc-mysql)
2. 使用驱动提供的api操作
pom.xml

<properties>
	<r2dbc-mysql.version>1.0.5</r2dbc-mysql.version>
</properties>

    <dependencies>
        <dependency>
            <groupId>io.asyncer</groupId>
            <artifactId>r2dbc-mysql</artifactId>
            <version>${r2dbc-mysql.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

单元测试

    @Test
   public void testGetConnection() throws Exception{
       //1.获取连接工厂
       MySqlConnectionConfiguration config = MySqlConnectionConfiguration.builder()
               .host("123.57.132.54")
               .username("root")
               .password("zyl000419")
               .database("index_demo")
               .build();
       MySqlConnectionFactory factory = MySqlConnectionFactory.from(config);

       //2.获取到连接,发送sql
       Mono.from(factory.create())
               .flatMapMany(connection ->
                    connection
                           .createStatement("SELECT * FROM t_author WHERE id = ?id")
                           .bind("id",1L)
                           .execute()
               )//每一个连接会产生很多数据(result)
               .flatMap(result -> {
                   return result.map(readable -> {
                       Long id = readable.get("id", Long.class);
                       String name = readable.get("name", String.class);
                       return new Author(id,name);
                   });
               })
               .subscribe(System.out::println);

       System.in.read();
   }

参数赋值
在这里插入图片描述

spring data r2dbc-整合与自动配置

SpringBoot对r2dbc自动配置
R2dbcAutoConfiguration:主要配置连接工厂,连接池
R2dbcDataAutoConfiguration:
r2dbcEntityTemplate:操作数据库的响应式客户端,提供crud Api数据类型映射关系,转换器
自定义R2dbcCustomConversions转换器组件
数据类型 int -> integer; varchar->string
R2dbcRepositoriesAutoConfiguration:开启springboot声明式接口方式的crud
spring data 提供了基础的crud接口,不用写任何实现的情况下,可以直接具有crud功能
R2dbcTransactionManager:事物管理

导入相关依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
			<artifactId>spring-data-r2dbc</artifactId>
        </dependency>

编写application.yml配置
调整日志级别,打印sql语句

spring:
  r2dbc:
    url: r2dbc:mysql://your_host:3306
    username: root
    password: your_password
    name: your_database
logging:
  level:
    org.springframework.r2dbc: debug

database client & r2dbcEntityTemplate api

创建数据库映射实体

@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("t_author")
public class Author {

    private Long id;
    private String name;

}

R2dbcEntityTemplate: crudApi,join操作不好做

    @Autowired
    private R2dbcEntityTemplate template;

    @Test
    public void testR2dbcEntityTemplate() throws Exception{
        //1.构造查询条件
        Criteria criteria = Criteria.empty()
                .and("id").is(1L)
                .and("name").is("zyl");
        //2.封装为查询对象
        Query query = Query.query(criteria);
        template.select(query, Author.class)
                .subscribe(System.out::println);
        System.in.read();
    }

DatabaseClient:数据库客户端,贴近底层,join操作好做

    @Autowired
    private DatabaseClient databaseClient;
    
    @Test
    public void testJoin() throws IOException {
        databaseClient.sql("SELECT  * FROM t_author WHERE id = ?id")
                .bind("id",1L)
                .fetch()
                .all()
                .map(map -> {
                    String id = String.valueOf(map.get("id"));
                    String name = String.valueOf(map.get("name"));
                    return new Author(Long.valueOf(id), name);
                })
                .subscribe(System.out::println);
        System.in.read();
    }

spring data r2dbc

开启r2dbc仓库功能,jpa

@EnableR2dbcRepositories
@Configuration
public class R2dbcConfig {

    
}

1.写Repositories接口,默认继承一些crud方法
QBC: Query By Ctiteric
QBE: Query By Example

@Repository
public interface AuthorRepositories extends R2dbcRepository<Author,Long> {

}

测试:
复杂调价查询:
1.QBE Api(不推荐)
2.自定义方法
3.自定义sql
repositeries起名有提示,按sql起名

@Repository
public interface AuthorRepositories extends R2dbcRepository<Author,Long> {

    /**
     * where id in ? and name like ?
     */
    Flux<Author> findAllByIdInAndNameLike(Collection<Long> ids, String name);
}

测试复杂查询

    @Test
    public void testRepositories() throws IOException {
        authorRepositories.findAll()
                .subscribe(System.out::println);
        authorRepositories.findAllByIdInAndNameLike(List.of(1L),"z%")
                        .subscribe(System.out::println);
        System.in.read();
    }

控制台打印sql

SELECT t_author.id, t_author.name 
FROM t_author 
WHERE t_author.id IN (?) AND (t_author.name LIKE ?)

缺点:仅限单表crud
测试多表复杂查询
自定义注解@Query(),指定sql语句
1-1查询:一个图书有一个作者
1-n查询:一个作者写了多本图书
实体类Book

@Data
@Table("t_book")
public class Book {

    @Id
    private Long id;
    private String title;
    private Long authorId;
    private LocalDateTime publishTime;

}

repositorues

@Repository
public interface BookRepositories extends R2dbcRepository<Book,Long> {

    @Query("SELECT book.title,author.name " +
            "FROM index_demo.t_book book " +
            "LEFT JOIN index_demo.t_author author " +
            "ON book.author_id = author.id " +
            "WHERE book.id = :bookId")
    Mono<Book> findBookAndAuthor(Long bookId);
}

绑定查询参数:
在这里插入图片描述
自定义结果转换器

@ReadingConverter//读取数据库数据时,把row->book
public class BookConverter implements Converter<Row, Book> {
    @Override
    public Book convert(Row source) {
         if (ObjectUtils.isEmpty(source)) {
            return new Book();
        }
        String title = source.get("title", String.class);
        String authorName = source.get("name", String.class);
        Book book = new Book();
        Author author = new Author();
        author.setName(authorName);
        book.setAuthor(author);
        book.setTitle(title);
        return book;
    }
}

配置自定义类型转换器

@EnableR2dbcRepositories
@Configuration
public class R2dbcConfig {

    /**
     * 将自己定义的转换器加入进去
     */
    @Bean
    @ConditionalOnMissingBean
    public R2dbcCustomConversions conversions () {
        return R2dbcCustomConversions.of(MySqlDialect.INSTANCE,new BookConverter());
    }

}

测试

    @Test
    public void testQueryMulti() throws Exception{
        bookRepositories.findBookAndAuthor(1L)
                .subscribe(System.out::println);
        System.in.read();
    }

总结:
1.spring data R2DBC 基础的CRUD用R2dbcRepository 提供好了
2.自定义复杂的sql(单表):@Query()
3.多表查询复杂结果集合:DatabaseClient自定义sql,自定义结果封装
@Query+自定义converter实现结果封装
自定义转换器问题:对以前crud产生影响
Converter<Row,Book>:把数据库每一行row,转换成book
工作时机:spring data发现方法签名只要是返回Book,利用自定义转换器工作
所有对Book结果封装都使用转换器,包括单表查询
解决方法1:新VO+新的Repositories+自定义类型转换器
BookauthorVO

@Data
public class BookAuthorVO {

    private Long id;
    private String title;
    private Long authorId;
    private LocalDateTime publishTime;

    private Author author;//每一本书有唯一作者
}

自定义BookAuthorRepositories

@Repository
public interface BookAuthorRepositories extends R2dbcRepository<BookAuthorVO,Long> {

    @Query("SELECT book.title,author.name " +
            "FROM index_demo.t_book book " +
            "LEFT JOIN index_demo.t_author author " +
            "ON book.author_id = author.id " +
            "WHERE book.id = :bookId")
    Mono<Book> findBookAndAuthor(@Param("bookId")Long bookId);
}

自定义BookAuthor转换器

@ReadingConverter//读取数据库数据时,把row->book
public class BookAuthorConverter implements Converter<Row, BookAuthorVO> {
    @Override
    public BookAuthorVO convert(Row source) {
        if (ObjectUtils.isEmpty(source)) {
            return new BookAuthorVO();
        }
        String title = source.get("title", String.class);
        String authorName = source.get("name", String.class);
        BookAuthorVO book = new BookAuthorVO();
        Author author = new Author();
        author.setName(authorName);
        book.setAuthor(author);
        book.setTitle(title);
        return book;
    }
}

解决方法2:自定义转换器中增加判断
source.getMetaData.contains(“”)
让converter兼容更多表结构(推荐!!!)

@ReadingConverter//读取数据库数据时,把row->book
public class BookAuthorConverter implements Converter<Row, BookAuthorVO> {
    @Override
    public BookAuthorVO convert(Row source) {
        if (ObjectUtils.isEmpty(source)) {
            return new BookAuthorVO();
        }
        String title = source.get("title", String.class);
        BookAuthorVO book = new BookAuthorVO();
        book.setTitle(title);
        if (source.getMetadata().contains("name")) {
            String authorName = source.get("name", String.class);
            Author author = new Author();
            author.setName(authorName);
            book.setAuthor(author);
        }
        return book;
    }
}

经验:
1-1/1-n都需要自定义结果集
spring data R2dbc:自定义converter指定结果封装
mybatis:自定义resultMap标签来封装

BufferUntilChanged操作

如果下一个判定值,比起上一个发生了变化,就开一个新buffer保存
如果没有变化,就保存到原buffer中
前提:数据已经提前排好序
groupBy:允许乱序
作者有很多图书. 1:n
sql

SELECT author.name,author.id,book.title
FROM index_demo.t_author author
LEFT JOIN index_demo.t_book book
ON author.id = book.author_id
WHERE author.id = 1;

测试

    @Test
    public void testAuthorBookTest() throws Exception {
        databaseClient.sql("SELECT author.name,author.id,book.title " +
                        "FROM index_demo.t_author author " +
                        "LEFT JOIN index_demo.t_book book " +
                        "ON author.id = book.author_id " +
                        "WHERE author.id = ?id")
                .bind("id", 1L)
                .fetch()
                .all()
                .bufferUntilChanged(rowMap -> Long.parseLong(String.valueOf(rowMap.get("id"))))
                //id发生变化,重新分组,若是对象比较,需重写equals()方法
                .map(list -> {
                    if (CollectionUtils.isEmpty(list)) {
                        return Collections.emptyList();
                    }
                    List<Book> bookList = list.stream()
                            .map(item -> {
                                String title = String.valueOf(item.get("title"));
                                return Book.builder()
                                        .title(title)
                                        .build();
                            })
                            .toList();
                    return Author.builder()
                            .id(Long.valueOf(String.valueOf(list.get(0).get("id"))))
                            .name(String.valueOf(list.get(0).get("name")))
                            .bookList(bookList);
                })
                .subscribe(System.out::println);
        System.in.read();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1401046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浙江建筑模板批发 — 广西源头厂家供应

在建筑行业中&#xff0c;高质量的模板材料对于确保工程的顺利进行和质量至关重要。我们的浙江强度高耐水建筑模板&#xff0c;直接来自广西的源头厂家&#xff0c;以其出色的性能和质量&#xff0c;成为建筑项目的理想选择。 产品特性 高强度稳定性&#xff1a;精选优质材料制…

Java--类继承

文章目录 主要内容一.学生类1.源代码代码如下&#xff08;示例&#xff09;: 2.结果 二.交通工具类1.源代码代码如下&#xff08;示例&#xff09;: 2.结果 三.圆类1.源代码代码如下&#xff08;示例&#xff09;: 2.结果 总结 主要内容 学生类交通工具类圆类 一.学生类 具有…

2.RHCSA启动配置

rht-clearcourse 0 #重置练习环境 rht-setcourse rh134 #切换CSA练习环境 cat /etc/rht #查看当前环境 virt-manager #打开KVM控制台 rht-vmctl start classroom #必做&#xff0c;start all不会包含classroom&#xff0c;需…

Appium 环境配置

Appium 是一个开源的、跨平台的测试框架&#xff0c;可以用来测试 Native App、混合应用、移动 Web 应用&#xff08;H5 应用&#xff09;等&#xff0c;也是当下互联网企业实现移动自动化测试的重要工具。Appium 坚持的测试理念&#xff1a; •无需用户对 App 进行任何修改或…

神策 CDP 获评中国软件评测中心「优秀大数据产品」

近日&#xff0c;中国软件评测中心在第十三届软件大会上揭晓了「第十五期优秀大数据产品、解决方案和案例测评结果」。神策数据基于客户旅程编排的客户数据平台&#xff08;CDP&#xff09;1.3.0 凭借出色的产品能力获评「优秀大数据产品」&#xff0c;并获得大数据基础设施类产…

[网络编程]UDP协议,基于UDP协议的回显服务器

目录 1.UDP协议介绍 2.UDP协议在Java中的类 2.1DatagramSocket类 2.2DatagramPacket 3.回显服务器 3.1Sever端 3.2Client端 1.UDP协议介绍 UDP协议是一种网络协议&#xff0c;它是无连接的&#xff0c;全双工&#xff0c;并且是面向数据报&#xff0c;不可靠的一种协议…

C语言实现简单的扫雷游戏

目录 1 -> test.c 2 -> game.c 3 -> game.h 1 -> test.c #define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void menu() {printf("************************************\n");printf("********* 1.play ********\n&quo…

【51单片机】动态数码管

0、前言 参考&#xff1a; 普中51单片机开发攻略–A2.pdf 1、数码管介绍 上一章我们主要是介绍一位数码管的内部结构及控制原理。下面我们再来介 绍下多位数码管及动态显示原理的相关知识。 1.1 多位数码管简介 2、74HC245 和 74HC138 芯片介绍 2.1 74HC245 芯片简介 2.2 7…

JVM(上)

目录 一、JVM概述 一、JVM作用 二、JVM整体组成部分 二、JVM结构-类加载 一、类加载子系统概述 二、类加载过程 1.加载 2.链接 3.初始化&#xff08;类加载过程中的初始化&#xff09; 三、类加载器分类 大致分两类&#xff1a; 细致分类&#xff1a; 四、双亲委派机制 五、打…

线程和进程的区别(从JVM角度出发)

进程与线程的区别 线程具有许多传统进程所具有的特征&#xff0c;故又称为轻型进程(Light—Weight Process)或进程元&#xff1b;而把传统的进程称为重型进程(Heavy—Weight Process)&#xff0c;它相当于只有一个线程的任务。在引入了线程的操作系统中&#xff0c;通常一个进…

【Godot4自学手册】第二节主人公设置

继续学习Godot&#xff0c;今天是第二节的内容&#xff0c;本节主要完成游戏玩家的设置&#xff0c;将玩家展现在场景中。 一、新建一个主场景 首先在场景面板中单击2D场景&#xff0c;如图。 这样我们就有了一个2D场景&#xff0c;我们将Node2D重新命名为“Main”&#xff…

使用Nginx和Fancyindex组合搭建文件下载站点详细教程

目录 简介 TIPS 1.下载Nginx 2. 安装Fancyindex和Nginx-Fancyindex-Theme模块 2.1 安装编译工具和依赖 2.2 下载Fancyindex和Nginx-Fancyindex-Theme 2.3 编译Nginx并包括Fancyindex 3. 配置Nginx 4.体验 4.1light主题 4.2dark主题 后记 简介 当使用Nginx和Fancyinde…

【轮式平衡机器人】——角度/速度/方向控制分析软件控制框架

轮式平衡机器人具有自不稳定性&#xff0c;可类比一级倒立摆系统的控制方法&#xff0c;常见有反馈线性化方法、非线性PID控制、自适应控制、自抗扰控制&#xff0c;还有改进的传统缺乏对外界干扰和参数改变鲁棒性的滑模变结构控制。我们采用较为简单的双闭环PID控制实现平衡模…

C++入门学习(九)浮点数

浮点型主要有两种&#xff1a; floatdouble 占用空间有效数字范围float4字节7位有有效数字double8字节15~16位有效数字 为什么float 有效数位 7 or 8 位&#xff0c;double 15 or 16 位&#xff1f; https://zhidao.baidu.com/question/1182732476020869219.htmlhttps://zhid…

Arduino开发实例-SDS011粉尘检测传感器驱动

SDS011粉尘检测传感器驱动 文章目录 SDS011粉尘检测传感器驱动1、SDS011介绍2、硬件准备及接线3、代码实现在本文中,将介绍如何使用 Arduino 动粉尘传感器 SDS011 制作空气质量监测系统。 1、SDS011介绍 粉尘本身根据它们的大小分为两类。 直径在2.5至10微米之间的称为粗颗粒…

【算法详解】力扣162.寻找峰值

​ 目录 一、题目描述二、思路分析 一、题目描述 力扣链接&#xff1a;力扣162.寻找峰值 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回 任何一个…

【音视频】基于ffmpeg对视频的切割/合成/推流

背景 基于FFmpeg对视频进行切割、合成和推流的价值和意义在于它提供了一种高效、灵活且免费的方式来实现视频内容的定制、管理和分发。通过FFmpeg&#xff0c;用户可以轻松地剪辑视频片段&#xff0c;根据需要去除不必要的部分或提取特定时间段的内容&#xff0c;从而优化观看…

网络安全行业热门认证证书合集

网络安全认证证书&#xff0c;就和学历一样是敲门砖&#xff0c;拿到了可以用不到&#xff0c;但不能没有&#xff1b;技术大牛可以没有证书&#xff0c;但普通人不能没有。 1.初级入门&#xff1a; 就像学历在职场上展示一个人的基本素养一样&#xff0c;网络安全认证证书可以…

机器视觉技术与应用实战(BLOB分析)

我发现写blob分析&#xff08;Binary Large Object)相应的处理函数的文章非常少。那就写一写关于blob分析相关的文章。 blob工具也叫做斑点工具&#xff0c;先对图像进行二值化&#xff0c;对图像中连通区域进行计算&#xff0c;计算几何特征。 BLOB分析功能&#xff1a; 1、…

磁盘分区机制

lsblk查看分区 Linux分区 挂载的经典案例 1. 虚拟机增加磁盘 点击这里&#xff0c;看我的这篇文章操作 添加之后&#xff0c;需要重启系统&#xff0c;不重启在系统里看不到新硬盘哦 出来了&#xff0c;但还没有分区 2. 分区 还没有格式化 3. 格式化磁盘 4. 挂载 5. 卸载…