R2DBC-响应式数据库

简单查询

基于全异步,响应式,消息驱动
用法:
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();
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【目标检测】YOLOv5算法实现(九):模型预测

本系列文章记录本人硕士阶段YOLO系列目标检测算法自学及其代码实现的过程。其中算法具体实现借鉴于ultralytics YOLO源码Github&#xff0c;删减了源码中部分内容&#xff0c;满足个人科研需求。   本系列文章主要以YOLOv5为例完成算法的实现&#xff0c;后续修改、增加相关模…

成绩等级分数段查询(python条件分支语句match...case...)

根据有效分数序列及等级差值&#xff0c;计算并打印等级相应分数区间。 (笔记模板由python脚本于2024年01月20日 23:57:32创建&#xff0c;本篇笔记适合会条件分支语句的初学者的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&…

视频怎么添加字幕?这几款工具很实用

视频怎么添加字幕&#xff1f;现在&#xff0c;视频已经成为人们获取信息和娱乐的主要方式之一。然而&#xff0c;很多时候&#xff0c;我们想要更深入地理解视频内容&#xff0c;或者为听力障碍者提供帮助&#xff0c;就需要添加字幕。那么&#xff0c;如何为视频添加字幕呢&a…

《游戏-02_2D-开发》

基于《游戏-01_2D-开发》&#xff0c; 继续制作游戏&#xff1a; 首先给人物添加一个2D重力效果 在编辑的项目设置中&#xff0c; 可以看出unity默认给的2D重力数值是-9.81&#xff0c;模拟现实社会中的重力效果 下方可以设置帧率 而Gravity Scale代表 这个数值会 * 重力 还…

Git将某个文件合并到指定分支

企业开发中&#xff0c;经常会单独拉分支去做自己的需求开发&#xff0c;但是某些时候一些公共的配置我们需要从主线pull&#xff0c;这时候整个分支merge显然不合适 1.切换至待合并文件的分支 git checkout <branch>2.将目标分支的单个文件合并到当前分支 git checkou…

maven 基本知识/1.17

maven ●maven是一个基于项目对象模型(pom)的项目管理工具&#xff0c;帮助管理人员自动化构建、测试和部署项目 ●pom是一个xml文件&#xff0c;包含项目的元数据&#xff0c;如项目的坐标&#xff08;GroupId,artifactId,version )、项目的依赖关系、构建过程 ●生命周期&…

Servlet系列:两种创建方式(xml,注解)

一、使用web.xml的方式配置&#xff08;Servlet2.5之前使用&#xff09; 在早期版本的Java EE中&#xff0c;可以使用XML配置文件来定义Servlet。在web.xml文件中&#xff0c;可以定义Servlet的名称、类名、初始化参数等。然后&#xff0c;在Java代码中实现Servlet接口&#x…

第三课:GPT

文章目录 第三课&#xff1a;GPT1、学习总结&#xff1a;GPT出现的原因GPT的方法原理目前存在的问题无监督的预训练优化目标模型结构 监督微调课程ppt及代码地址 2、学习心得&#xff1a;3、经验分享&#xff1a;4、课程反馈&#xff1a;5、使用MindSpore昇思的体验和反馈&…

Pyro —— Flames

目录 Differences with legacy pyro Lifespan Outputs flame场是火和爆炸模拟的重要部分&#xff0c;存储反应物&#xff08;如fuel&#xff09;剩余寿命&#xff1b;该场可通过发射源补充&#xff0c;解算器会减少其值并生成对应输出&#xff08;如smoke、temperature&…

C#,入门教程(23)——数据类型转换的一点基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(22)——函数的基础知识https://blog.csdn.net/beijinghorn/article/details/124181689 先简单回顾一下&#xff0c;C#的数据类型大致有这样一些&#xff1a; &#xff08;1&#xff09;原始类型&#xff1a;byte, bool, int, doubl…

学习笔记——克里金插值

有一篇大神的文章写得非常的具体&#xff0c; https://xg1990.com/blog/archives/222 下面写下一些学习笔记&#xff1a; 1、关于克里金插值的基本原理 克里金插值来源于地理学&#xff0c;它的前提是地理学第一定律&#xff1a;所有事物都与其他事务相关&#xff0c;但是近…

Python爬蟲海外動態IP防止被封的方法 - okey proxy

在使用Python進行網路爬蟲過程中&#xff0c;我們常遇到一個問題&#xff0c;就是如何防止我們的爬蟲被目標網站封禁&#xff1f;其中一種有效的方法是使用海外動態IP代理。 代理伺服器就像是你和目標網站之間的中間人。而動態IP代理則意味著&#xff0c;每次連接都會使用一個…

Docker(四)操作容器

作者主页&#xff1a; 正函数的个人主页 文章收录专栏&#xff1a; Docker 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01; 操作 Docker 容器 容器是 Docker 又一核心概念。 简单的说&#xff0c;容器是独立运行的一个或一组应用&#xff0c;以及它们的运行态环境…

5G基站节能及数字化管理解决方案

截至2023年10月&#xff0c;我国5G基站总数达321.5万个&#xff0c;占全国通信基站总数的28.1%。然而&#xff0c;随着5G基站数量的快速增长&#xff0c;基站的能耗问题也逐渐日益凸显&#xff0c;基站的用电给运营商带来了巨大的电费开支压力&#xff0c;降低5G基站的能耗成为…

使 a === 1 a === 2 a === 3 为 true 的几种“下毒“方法

前言 这算得上是近些年的前端网红题了&#xff0c;曾经对这种网红题非常抵触&#xff0c;认为非常没有意义。 看到了不少人有做分享&#xff0c;有各种各样的方案&#xff0c;有涉及到 JS 非常基础的知识点&#xff0c;也不得不感叹解题者的脑洞之大。 但是&#xff0c;拿来…

redis远程连接不上解决办法

问题描述&#xff1a; redis远程服务端运行在192.168.3.90计算机上&#xff0c;客户端计算机&#xff08;ip:192.168.3.110&#xff09;通过redsi-cli.exe客户端工具连接时&#xff0c;没有反应&#xff0c;连接不上。 如图所示&#xff1a; 解决步骤&#xff1a; 步骤一&…

UE5 植物生长材质_树根像目标缠绕(记录备忘)

需要在三维软件中将树根缠绕物体的形态预先做好&#xff0c;将管状树根uv方形排布&#xff0c;模型默认材质为渐变上黑下白&#xff0c;导入引擎&#xff0c;注意制作树根尖端需要将左侧Masked数值由0.333修改为0

Java根据模板文件生成excel文件,同时将excel文件转换成图片

需求 需要将指定数据导出成表格样式的图片&#xff0c;如图 业务拆解 定义一个导出模板将得到的数据填入模板中&#xff0c;生成excel文件将ecxel文件转换成png格式的图片 代码实现 需要引入的依赖 <dependency><groupId>cn.hutool</groupId><artif…

6、梯度提升XGBoost(eXtreme Gradient Boosting)

XGBoost梯度提升 结构化数据最精确的建模技术。 在本节课中,我们将学习如何使用梯度增强来构建和优化模型。这种方法在Kaggle的许多竞争中占据主导地位,并在各种数据集上获得了最先进的结果。 本课程所需数据集夸克网盘下载链接:https://pan.quark.cn/s/9b4e9a1246b2 提取码…

JavaScript之ES6新特性02

模板字符串 模板字符串&#xff08;template string&#xff09;是增强版的字符串&#xff0c;用反引号&#xff08;&#xff09;标识。它可以当作普通字符串使用&#xff0c;也可以用来定义多行字符串&#xff0c;或者在字符串中嵌入变量 。 模版字符串特点 内容中可以直接…