R2DBC-响应式数据库

2024-01-21 13:44
文章标签 数据库 响应 r2dbc

本文主要是介绍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>

单元测试

    @Testpublic 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.获取到连接,发送sqlMono.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:3306username: rootpassword: your_passwordname: 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操作不好做

    @Autowiredprivate R2dbcEntityTemplate template;@Testpublic 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操作好做

    @Autowiredprivate DatabaseClient databaseClient;@Testpublic 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);
}

测试复杂查询

    @Testpublic 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 {@Idprivate 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> {@Overridepublic 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@ConditionalOnMissingBeanpublic R2dbcCustomConversions conversions () {return R2dbcCustomConversions.of(MySqlDialect.INSTANCE,new BookConverter());}}

测试

    @Testpublic 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> {@Overridepublic 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> {@Overridepublic 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;

测试

    @Testpublic 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();}

这篇关于R2DBC-响应式数据库的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/629739

相关文章

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

postgresql数据库基本操作及命令详解

《postgresql数据库基本操作及命令详解》本文介绍了PostgreSQL数据库的基础操作,包括连接、创建、查看数据库,表的增删改查、索引管理、备份恢复及退出命令,适用于数据库管理和开发实践,感兴... 目录1. 连接 PostgreSQL 数据库2. 创建数据库3. 查看当前数据库4. 查看所有数据库

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手