jedis的scan操作要注意cursor数据类型
环境
jedis3.0.0
背景
在使用jedis的"scan"操作获取redis中某些key时,发现总是出现类型转换的异常——"java.lang.ClassCastException: java.lang.String cannot be cast to [B"

其中,redis中存储的key是byte[]类型,用"scan"操作获取的所有key是封装到一个List<T>中,获取结果后直接通过Set.addAll()存到一个HashSet<byte[]>中,就在用forEach遍历该HashSet时抛出了异常。
Debug
Why
经过debug发现这跟调用"scan(cursor,params)"时传的"cursor"的类型有关。


如上两图所示:
- 当cursor为String类型时,调用的是Jedis类中的scan方法;
- 当cursor为byte[]类型时,调用的则是BinaryJedis中的scan方法。
Jedis类是BinaryJedis的子类

What
接下来看下两者的scan方法——
Jedis.scan(final String cursor, final ScanParams params):
@Override
public ScanResult<String> scan(final String cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(newcursor, results);
}
BinaryJedis.scan(final byte[] cursor, final ScanParams params):
public ScanResult<byte[]> scan(final byte[] cursor, final ScanParams params) {
checkIsInMultiOrPipeline();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
return new ScanResult<byte[]>(newcursor, rawResults);
}
可以发现,两者都是通过调用BinaryClient类的scan方法来获取数据,这些数据是一样的,只是两者在封装返回结果时的操作不同而已。BinaryJedis把byte[]类型的原始数据原封不动地返回,而Jedis则是用SafeEncode把原始数据encode成String类型返回。
How
一开始没意识到scan("0",params)和scan("0".getBytes(),params)返回结果不同,直接用了前者,结果前者返回的是List<String>类型的数据,直接用addAll(ScanResult.getResult())方法放到HashSet<byte[]>中,而编译器这时是没有提示的,所以自然而然,在遍历HashSet时就抛出了异常。


注:ScanResult提供两个方法获取游标,分别是getCursor()和getCursorAsBytes(),前者是String类型,后者是byte[]类型,使用时需要注意。
拓展
此时又产生了新的疑惑,会不会在ScanParams中也存在类似的问题?于是进ScanParams类查看

发现这里对match方法进行了重载(Overload),传入byte[]和String类型的参数结果是一样的。所以ScanParams的pattern可以用String或者byte[]。
启发
在开发中,一定一定一定要注意变量类型,尤其是集合中的泛型。有必要的话,在类型转换前或者在集合类的操作中对变量进行类型检查。
jedis的scan操作要注意cursor数据类型的更多相关文章
- jedis keys和scan操作
关于redis的keys命令的性能问题 KEYS pattern 查找所有符合给定模式 pattern 的 key . KEYS * 匹配数据库中所有 key . KEYS h?llo 匹配 hell ...
- Jedis运用scan删除正则匹配的key
jedis运用scan删除正则匹配的key 我们都知道用keys *进行查询key的时候会进行堵塞,导致redis整体不可用,而使用scan命令则不会. RedisServiceImpl中sca ...
- 第三百零六节,Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置
Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...
- Major compaction时的scan操作
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u014393917/article/details/24419355 Major compactio ...
- 四 Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置
Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...
- SQLAlchemy02 /SQLAlchemy对数据的增删改查操作、属性常用数据类型详解
SQLAlchemy02 /SQLAlchemy对数据的增删改查操作.属性常用数据类型详解 目录 SQLAlchemy02 /SQLAlchemy对数据的增删改查操作.属性常用数据类型详解 1.用se ...
- SQLAlchemy(二):SQLAlchemy对数据的增删改查操作、属性常用数据类型详解
SQLAlchemy02 /SQLAlchemy对数据的增删改查操作.属性常用数据类型详解 目录 SQLAlchemy02 /SQLAlchemy对数据的增删改查操作.属性常用数据类型详解 1.用se ...
- Java 使用Jedis和RedisTemplate操作Redis缓存(SpringBoot)
package com.example.redis.controller; import com.example.redis.entity.User; import com.example.redis ...
- 存储引擎和表的操作(mysql中的数据类型、完整性约束)
一.存储引擎 .概念 MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力. 通过选择不同的技术 ...
随机推荐
- lodap问题集锦
1.分页打印时,同一行显示在不同页内 ,调整行分页粒度 LODOP.SET_PRINT_STYLEA(0, "TableRowThickNess", 40);
- [转]敏捷开发需求管理(产品backlog)
传统的瀑布工作模式使用详细的需求说明书来表达需求,需求人员负责做需求调研,根据调研情况编制详细的需求说明书,进行需求评审,评审之后签字确认交给研发团队设计开发.在这样的环境下,需求文档是信息传递的主体 ...
- Vue 列表动画实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 安装scipy失败提示lapack not found
从python库网站下载numpy+mkl合集包通过pip安装在下载scipy安装包通过pip安装即可
- HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite r ...
- win2d 画出好看的图形
本文告诉大家,win2d 不需要从零开始做,以前做出来的很多库其实只需要做很小修改就可以做出好看的效果,而且用在 UWP 上.本文修改原先 大神写的 GDI 图形到 win2d 上,而且可以运行起来 ...
- 【codeforces 789B】Masha and geometric depression
[题目链接]:http://codeforces.com/contest/789/problem/B [题意] 让你一个一个地写出等比数列的每一项 (注意是一个一个地写出); 有m个数字不能写; 且数 ...
- linux下svn清除非版本控制文件的方法
使用svn status命令,文件名前面显示问好的就是非版本控制的文件
- codeforce 379(div.2)
A.B略 C题 ——贪心,二分查找: 对于每一个a[i], 在d中二分查找 s-b[i],注意不要忘记计算速度为x时需要花费的最小时间,以及整数范围为64位整数 1 #include <cstd ...
- Linux 内核总线
一个总线是处理器和一个或多个设备之间的通道. 为设备模型的目的, 所有的设备都通过 一个总线连接, 甚至当它是一个内部的虚拟的,"平台"总线. 总线可以插入另一个 - 一个 USB ...