Spring Boot 与 R2DBC 整合
R2DBC 是 "Reactive Relational Database Connectivity"的简称。R2DBC 是一个 API 规范的倡议,声明对于访问关系型数据库驱动实现了一些响应式的API。
R2DBC的诞生为了非阻塞的应用栈, 使用很少的线程可以处理大量的并发同时减少硬件资源。大量的应用还是使用的关系型数据库,然而很多 NoSQL 数据提供了响应式客户端,并不是所有的项目都适合迁移到 NoSQL。因此,R2DBC 应运而生。
R2DBC 特点
- 对于 R2DBC 的驱动实例,Spring 支持基于Java 的
@Connfiguration的配置 R2dbcEntityTemplate作为实体绑定的核心操作类- 整合了Spring Conversion Service 丰富的对象映射
- 基于注解元数据映射关系
- 自动实现 Reposity 接口,包含支持自定义的查询方法
使用
接下来通过一个官方的实例来演示
依赖 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<version>3.4.8</version>
<scope>compile</scope>
</dependency>
</dependencies>
定义 Person 实体
public class Person {
private final String id;
private final String name;
private final int age;
public Person(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
测试
import com.example.springreactivedemo.model.Person;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import reactor.test.StepVerifier;
public class Test1 {
private static final Log log = LogFactory.getLog(Test1.class);
public static void main(String[] args) {
ConnectionFactory connectionFactory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
R2dbcEntityTemplate template = new R2dbcEntityTemplate(connectionFactory);
template.getDatabaseClient().sql("CREATE TABLE person" +
"(id VARCHAR(255) PRIMARY KEY," +
"name VARCHAR(255)," +
"age INT)")
.fetch()
.rowsUpdated()
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
template.insert(Person.class)
.using(new Person("joe", "Joe", 34))
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
template.select(Person.class)
.first()
.doOnNext(it -> log.info(it))
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
}
}
运行结果:
15:34:40.101 [main] DEBUG org.springframework.r2dbc.core.DefaultDatabaseClient - Executing SQL statement [INSERT INTO person (id, name, age) VALUES ($1, $2, $3)]
15:34:40.103 [main] DEBUG io.r2dbc.h2.client.SessionClient - Request: INSERT INTO person (id, name, age) VALUES ($1, $2, $3) {1: 'joe', 2: 'Joe', 3: 34}
Exception in thread "main" java.lang.AssertionError: expectation "expectNextCount(1)" failed (expected: count = 1; actual: counted = 0; signal: onError(java.lang.IllegalStateException: Required identifier property not found for class com.example.springreactivedemo.model.Person!))
at reactor.test.MessageFormatter.assertionError(MessageFormatter.java:115)
at reactor.test.MessageFormatter.failPrefix(MessageFormatter.java:104)
at reactor.test.MessageFormatter.fail(MessageFormatter.java:73)
at reactor.test.MessageFormatter.failOptional(MessageFormatter.java:88)
通过运行官方文档的实例出现了以上的报错信息,我们来看一下错误信息,Required identifier property not found for class com.example.springreactivedemo.model.Person! , Person 要求一个唯一属性,将 Person 类 id 增加了注解@Id , 再次执行成功,日志如下。
15:38:06.806 [main] DEBUG org.springframework.r2dbc.core.DefaultDatabaseClient - Executing SQL statement [INSERT INTO person (id, name, age) VALUES ($1, $2, $3)]
15:38:06.808 [main] DEBUG io.r2dbc.h2.client.SessionClient - Request: INSERT INTO person (id, name, age) VALUES ($1, $2, $3) {1: 'joe', 2: 'Joe', 3: 34}
15:38:06.847 [main] DEBUG io.r2dbc.h2.client.SessionClient - Request: CALL H2VERSION()
15:38:06.847 [main] DEBUG io.r2dbc.h2.client.SessionClient - Response: org.h2.result.LocalResultImpl@72c927f1 columns: 1 rows: 1 pos: -1
15:38:06.847 [main] DEBUG org.springframework.r2dbc.core.DefaultDatabaseClient - Executing SQL statement [SELECT person.* FROM person LIMIT 1]
15:38:06.853 [main] DEBUG io.r2dbc.h2.client.SessionClient - Request: SELECT person.* FROM person LIMIT 1
15:38:06.854 [main] DEBUG io.r2dbc.h2.client.SessionClient - Response: org.h2.result.LocalResultImpl@1c32886a columns: 3 rows: 1 pos: -1
15:38:06.876 [main] INFO com.example.springreactivedemo.client.Test1 - Person [id=joe, name=Joe, age=34]
Spring Boot 整合 R2DBC 流程
1. 创建 ConnectionFactory 和 R2dbcEntityTemplate
@Configuration
public class ApplicationConfiguration extends AbstractR2dbcConfiguration {
@Override
@Bean
public ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(H2ConnectionConfiguration.builder()
.url("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
.build());
}
@Bean
public R2dbcEntityTemplate r2dbcEntityTemplate() {
return new R2dbcEntityTemplate(connectionFactory());
}
}
2. CRUD 使用
@RestController
@Slf4j
public class PersonController {
private R2dbcEntityTemplate r2dbcEntityTemplate;
public PersonController(R2dbcEntityTemplate r2dbcEntityTemplate) {
this.r2dbcEntityTemplate = r2dbcEntityTemplate;
// 创建表结构
r2dbcEntityTemplate.getDatabaseClient().sql("drop table person if exists; CREATE TABLE person" +
"(id VARCHAR(255) PRIMARY KEY," +
"name VARCHAR(255)," +
"age INT)").fetch().rowsUpdated().subscribe();
}
@PostMapping("/save")
public Mono<Person> insert(@RequestBody Person person) {
return r2dbcEntityTemplate.insert(Person.class).using(person);
}
@GetMapping("/list")
public Flux<Person> list() {
return r2dbcEntityTemplate.select(Query.empty(), Person.class);
}
@PutMapping("/update")
public void update(@RequestBody Person person) {
r2dbcEntityTemplate.update(Person.class)
.inTable("person") //可以指定 table
.matching(Query.query(Criteria.where("id").is(person.getId())))
.apply(Update.update("name", person.getName())).subscribe();
}
@DeleteMapping("/delete")
public Mono<Integer> delete(@RequestBody Person person) {
return r2dbcEntityTemplate.delete(Person.class).matching(Query.query(Criteria.where("id").is(person.getId()))).all();
}
}
总结
Spring Boot 整合 R2DBC 简单实例使用完成,需要注意的是响应式编程和之前命令式编程有很大的区别,在写update方法中,在 r2dbcEntityTemplate 执行 update 最后没有调用 subscribe,导致 update方法没有执行,在响应式编程中定义的方法流程需要通过触发才会执行。代码里面使用 subscribe的方式来触发调用,还可以将执行 update返回的值 Mono,这样也会触发执行。
参考:
https://docs.spring.io/spring-data/r2dbc/docs/current/reference/html/#introduction
Spring Boot 与 R2DBC 整合的更多相关文章
- Spring Boot 2.x整合Redis
最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...
- spring boot 2.0 整合 elasticsearch6.5.3,spring boot 2.0 整合 elasticsearch NoNodeAvailableException
原文地址:spring boot 2.0 整合 elasticsearch NoNodeAvailableException 原文说的有点问题,下面贴出我的配置: 原码云项目地址:https://gi ...
- Spring Boot入门 and Spring Boot与ActiveMQ整合
1.Spring Boot入门 1.1什么是Spring Boot Spring 诞生时是 Java 企业版(Java Enterprise Edition,JEE,也称 J2EE)的轻量级代替品.无 ...
- Spring Boot和Dubbo整合
provider端 POM依赖 <dependencies> <dependency> <groupId>org.springframework.boot</ ...
- 转-Hive/Phoenix + Druid + JdbcTemplate 在 Spring Boot 下的整合
Hive/Phoenix + Druid + JdbcTemplate 在 Spring Boot 下的整合 http://blog.csdn.net/balabalayi/article/detai ...
- RabbitMQ入门:在Spring Boot 应用中整合RabbitMQ
在上一篇随笔中我们认识并安装了RabbitMQ,接下来我们来看下怎么在Spring Boot 应用中整合RabbitMQ. 先给出最终目录结构: 搭建步骤如下: 新建maven工程amqp 修改pom ...
- Spring Boot与ActiveMQ整合
Spring Boot与ActiveMQ整合 1使用内嵌服务 (1)在pom.xml中引入ActiveMQ起步依赖 <dependency> <groupId>org.spri ...
- Spring Boot 2.X整合Spring-cache,让你的网站速度飞起来
计算机领域有人说过一句名言:“计算机科学领域的任何问题都可以通过增加一个中间层来解决”,今天我们就用Spring-cache给网站添加一层缓存,让你的网站速度飞起来. 本文目录 一.Spring Ca ...
- Spring Boot 2.0 整合携程Apollo配置中心
原文:https://www.jianshu.com/p/23d695af7e80 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够 ...
随机推荐
- 配置Oracle遇到问题<一>
1, 将D:\app\product\11.2.0\dbhome_1\NETWORK复制到D:\app\product\instantclient_11_2.为了处理: 12154错误,不过没有解决. ...
- POJ 2299 Ultra-QuickSort 求逆序数 线段树或树状数组 离散化
我用的线段树写的. num数组表示已插入的数值的个数. 由于a[i]数值很大,但是n不是很大,所以要离散化处理 9 1 0 5 4 离散化后 4 1 0 3 2 这样保证最大值不会超过n #inclu ...
- sed 大括号 sed {} 的作用详解
今天看别人写的脚本的时候,看到了sed -r {} 我看网上对于这个的记录比较少,所以就写了这篇随笔. 先看一下效果 cat test.txt image: qqq/www/eee:TAG ...
- Centos6.7 minimal安装GitLab8.3.4配置LDAP、发邮件以及升级到GitLab8.5.4
建议使用非root账户安装,先同步系统时间: ntpdate cn.pool.ntp.org 1.创建用户gitlab 注意:centos下,adduser和useradd的命令效果是一样的,但ubu ...
- 大数据-Hadoop 伪分布模式
1. 分析 (1)配置集群 (2)启动.测试集群增.删.查 (3)执行WordCount案例 2. 执行步骤 (1)配置集群 (a)配置:hadoop-env.sh Linux系统中获取JDK的安装路 ...
- centos7 之 设置环境变量(转载)
设置centos环境变量,可以用export命令,也可以通过修改文件形式实现,本文以lavavel需要设置环境变量为例,将 /root/.config/composer/vendor/bin 路径加到 ...
- php漏洞 md5函数漏洞
0x01: 背景:php在处理哈希值时,用!=和==来比较的时候,如果哈希字符串以0E开头的时候,哈希值会默认为0,所以两个不同的字符串经过md5加密成哈希值,如果哈希值开头是0E的话,会默认成相等. ...
- Acunetix引入了Docker支持,扫描统计信息以及将漏洞发送到AWS WAF的功能
已针对Windows,Linux和macOS发布了新的Acunetix更新:14.2.210503151. 此Acunetix更新引入了Docker支持,针对每次扫描显示的新"扫描统计信息& ...
- 关于kong | API Gateway
目录 为什么需要 API 网关(more) kong的概念 为什么使用Kong Kong 的管理方式 高可扩展性的背后-插件机制 [前言]: Kong是一个云原生,高效,可扩展的分布式 API 网关. ...
- Java笔记——方法
1.方法 (1)概念:①解决事情的办法②实现功能的代码段. (2)优点:①提到代码的复用性②便于后期维护. (3)特点:①不调用不执行②方法不能嵌套,定义在类中方法外的位置. (4)定义方 ...