Redisson批量操作类RBuckets和管道利器RBatch
- 《Spring Boot 整合Redisson配置篇》
- 《Spring Boot 整合Redisson操作Redis基础篇》
- 《Redisson批量操作类RBuckets和管道利器RBatch》
摘要:使用Redisson的类RBuckets和RBatch批量操作Redis,减少网络请求次数。
综述
Redis的部署方式有单节点部署、哨兵方式部署、集群方式部署3种方式,这3中方式都使用的是原生的redis。本文基于单节点部署,使用的Spring Boot版本为2.5.x。
RBuckets批量操作
在Spring Boot项目中,通过RBuckets接口实现批量操作多个RBucket对象,官方示例如下:
RBuckets buckets = redisson.getBuckets();
Map<String, V> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// 利用Redis的事务特性,同时保存所有的通用对象桶,如果任意一个通用对象桶已经存在则放弃保存其他所有数据。
buckets.trySet(map);
// 同时保存全部通用对象桶。
buckets.set(map);
方法介绍:
- Map<String,V> get(String... keys):返回桶的key-value对。
- boolean trySet(Map<String,?> buckets):利用Redis的事务特性,同时保存所有的通用对象桶,如果任意一个通用对象桶已经存在则放弃保存其他所有数据。
- void set(Map<String,?> buckets):同时保存全部通用对象桶。
RBatch 批量操作
多个连续命令可以通过RBatch对象在一次网络会话请求里合并发送,这样省去了产生多个请求消耗的时间和资源。这在Redis中叫做管道。
RBatch管道功能就是REDIS的批量发送,实际上是客户端的功能,与服务端无关。相当于把多个请求的命令放在一个数据包通过TCP发送到服务端,然后客户端再一次性读取所有的命令回应。管道技术最显著的优势是提高了 redis 服务的性能。
/**
* 批量操作
*/
private void batchDemo() throws ExecutionException, InterruptedException {
Map<String, String> map = new HashMap<>();
map.put("abc", "testStr");
map.put("abcDemo", "redis");
redisUtils.setMassStrings(map);
log.info("String 测试数据:{}", redisUtils.getStr("abc") + " "
+ redisUtils.getStr("abcDemo"));
RBatch batch = redisUtils.createBatch();
// 模拟购物车场景,真实场景中请替换店铺ID shopId 和商品ID commodityId
String field = "shopId:commodityId";
// 把即将执⾏的命令放进 RBatch
RMapAsync testMap = batch.getMap("customerId:"+ 32L);
// 更新value,并返回上一次的值
String commodityNum = "mapValue" + String.valueOf((int)(Math.random()*9 + 100));
log.info("当前商品数量commodityNum是:{}", commodityNum);
testMap.putAsync(field, commodityNum);
testMap.putAsync("test2", "mapValue3");
testMap.putAsync("test2", "mapValue5");
testMap.putAsync("test:"+ String.valueOf((int)(Math.random()*900 + 100)), String.valueOf((int)(Math.random()*900 + 100)));
RAtomicLongAsync counter = batch.getAtomicLong("counter");
RFuture<Long> num = counter.incrementAndGetAsync();
// 执行RBatch中的全部命令,并返回执行结果
BatchResult result = batch.execute();
List list = result.getResponses();
log.info("Map Batch 执行结果:{}", list);
log.info("计数器当前值:{}", num.get());
}
执行batchDemo()后,控制台打印结果如下:
StudyRedissonController - String 测试数据:testStr redis
StudyRedissonController - 当前商品数量commodityNum是:mapValue106
StudyRedissonController - Map Batch 执行结果:[mapValue101, mapValue5, mapValue3, null, 8]
StudyRedissonController - 计数器当前值:8
测试用例主要介绍了Hash,顺便介绍一下它的使用场景:
- 存储结构化的数据,比如 Java 中的对象。其实 Java 中的对象也可以用 string 进行存储,只需要将对象序列化成 json 字符串就可以,但是如果这个对象的某个属性更新比较频繁的话,那么每次就需要重新将整个对象序列化存储,这样消耗开销比较大。可如果用 hash 来存储对象的每个属性,那么每次只需要更新要更新的属性就可以。
- 购物车场景。以业务线+用户id作为key,以店铺编号+商品的id作为存储的field,以选购商品数量作为键值对的value,这样就构成了购物车的三个要素。
在集群模式下,所有的命令会按各个槽所在的节点,筛选分配到各个节点并同时发送。每个节点返回的结果将会汇总到最终的结果列表里。上述demo中用到的工具类如下:
@Component
public class RedisUtils {
private RedisUtils() {
}
/**
* 默认缓存时间
*/
private static final Long DEFAULT_EXPIRED = 32000L;
/**
* 自动装配redisson client对象
*/
@Resource
private RedissonClient redissonClient;
/**
* 获取getBuckets 对象
*
* @return RBuckets 对象
*/
public RBuckets getBuckets() {
return redissonClient.getBuckets();
}
/**
* 读取缓存中的字符串,永久有效
*
* @param key 缓存key
* @return 字符串
*/
public String getStr(String key) {
RBucket<String> bucket = redissonClient.getBucket(key);
return bucket.get();
}
// ---------------- 批量操作 ------------------------
/**
* 获取RBatch
*
* @return RBatch
*/
public RBatch createBatch() {
return redissonClient.createBatch();
}
/**
* 批量移除缓存
*
* @param keys key 对象
*/
public void deleteBatch(String... keys) {
if (null == keys) {
return;
}
this.getKeys().delete(keys);
}
/**
* 批量缓存字符串,缺点:不可以设置过期时间
*
* @param map 缓存key-value
*/
public void setMassStrings(Map<String, String> map) {
if (MapUtils.isEmpty(map)) {
return;
}
RBuckets buckets = redissonClient.getBuckets();
// 同时保存全部通用对象桶。
buckets.set(map);
}
/**
* 批量缓存字符串,支持过期
*
* @param map 缓存key-value
* @param leaseTime 缓存有效期,必传
*/
public void setMassStrings(Map<String, String> map, long leaseTime) {
if (MapUtils.isEmpty(map)) {
return;
}
final long expireTime = leaseTime <= 0L ? DEFAULT_EXPIRED : leaseTime;
RBatch batch = redissonClient.createBatch();
map.forEach(new BiConsumer<String, String>() {
public void accept(String key, String value) {
batch.getBucket(key).setAsync(value, expireTime, TimeUnit.SECONDS);
}
});
batch.execute();
}
}
结束语
关于redisson中如何使用批量操作类RBuckets和管道利器RBatch就分享到这里,希望本文对大家的学习或者工作具有一定的参考和学习价值;如果有疑问,大家可以在评论区留言交流,也希望大家多多点赞关注。谢谢大家对楼兰胡杨的支持!
Reference
Redisson批量操作类RBuckets和管道利器RBatch的更多相关文章
- 模块(类)之间解耦利器:EventPublishSubscribeUtils 事件发布订阅工具类
如果熟悉C#语言的小伙伴们一般都会知道委托.事件的好处,只需在某个类中提前定义好公开的委托或事件(委托的特殊表现形式)变量,然后在其它类中就可以很随意的订阅该委托或事件,当委托或事件被触发执行时,会自 ...
- ASP.NET Web API 管道模型
ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...
- 在.NET中使用管道将输出流转换为输入流
最近在写一段代码,将本地文件压缩加密后发送到服务器,发送到服务器的类用一个输入流作为参数获取要上传的数据,而压缩类和加密类都是输出流. 如何将输出流转换为输入流,最直观的方法是缓存输出流的全部内容到内 ...
- 管道Pipe
管道Pipe java.nio.channels包中含有一个名为Pipe(管道)的类.广义上讲,管道就是一个用来在两个实体之间单向传输数据的导管.管道的概念对于Unix(和类Unix)操作系统的用户来 ...
- JAVA IO之管道流总结大全(转)
要在文本框中显示控制台输出,我们必须用某种方法“截取”控制台流.换句话说,我们要有一种高效地读取写入到System.out和 System.err 所有内容的方法.如果你熟悉Java的管道流Piped ...
- pipe管道
回顾: 进程间通信方式: 信号,管道 消息队列,共享内存,信号量 sokcet 信号: 本质就是软中断 signal(信号,函数指针); void func(int); kill(pid,signo) ...
- 【mongoDB查询进阶】聚合管道(二) -- 阶段操作符
https://segmentfault.com/a/1190000010826809 什么是管道操作符(Aggregation Pipeline Operators) mongoDB有4类操作符用于 ...
- java IO类简单介绍
一.流的概念 流是字节序列的抽象概念.流和文件的差别:文件是数据的静态存储形式,而流是指数据传输时的形态.文件只是流的操作对象之一.流按其操作的对象不同可以分为文件流.网络流.内存流.磁带流等.Jav ...
- springboot 整合redisson
整合代码已经过测试 1.pom <!-- redisson --> <dependency> <groupId>org.redisson</groupId&g ...
随机推荐
- 若没有任何实例包含Class Body 则enum被隐式声明为final
本文参考 今天在Java Language Specification上偶然看到一条关于枚举的语法特点说明 An enum declaration is implicitly final unless ...
- 显示调用C++中构造函数和析构函数(有什么弊端)
1.C++中, 构造函数和析构函数可以被显示调用. 显示调用默认构造函数的语法: a.A::A();(不能写成a.A();) , 显示调用非默认构造函数的语法: a.A::A(7);(不能写成a.A( ...
- C语言泛型编程——泛型冒泡排序
在实际编程中,常常会需要一些方法(函数),比如排序,它们具体实现基本一致,仅仅只有参数类型不同, 那么可不可以有一种通用的函数,不管是什么类型的参数都可以通用呢? 泛型编程:泛型即是指具有在多种数据类 ...
- 删除html标签或标签属性以及样式
JavaScript module for stripping HTML tags and/or HTML element attributes from strings. 安装 npm instal ...
- PAT B1051 复数乘法
输入样例: 2.3 3.5 5.2 0.4 输出样例: -8.68-8.23i 解题思路: 1.读入R1.P1.R2.P2. 2.A=(R1*R2)cos(P1+P2),B=(R1*R2)sin(P1 ...
- ssm项目框架搭建(增删改查案例实现)——(SpringMVC+Spring+mybatis项目整合)
Spring 常用注解 内容 一.基本概念 1. Spring 2. SpringMVC 3. MyBatis 二.开发环境搭建 1. 创建 maven 项目 2. SSM整合 2.1 项目结构图 2 ...
- EMS邮箱数据库常用命令(二)
1.查询邮箱数据库的使用空间 查询Exchange环境中所有邮箱数据库. 键入以下命令 Get-MailboxDatabase -Status | FL name,DatabaseSize 命令执行后 ...
- <!--[if IE]><style></style><![endif]-->
CSS hack就是为了让你的CSS代码兼容不同的浏览器,其中最难对付的就是IE浏览器的兼容性,因为它的版本很多,不过还好,微软发表声明已经不对IE8以下的版本进行维护了.但是我们也不能就认为不用学I ...
- Blazor组件自做五 : 使用JS隔离封装Google地图
Blazor组件自做五: 使用JS隔离封装Google地图 运行截图 演示地址 正式开始 1. 谷歌地图API 谷歌开发文档 开始学习 Maps JavaScript API 的最简单方法是查看一个简 ...
- 面试官:说一说Zookeeper中Leader选举机制
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 今天又是一个阳光明媚的一天,我又 ...