赞
踩
本篇文章已作废,请参考我的最新文章解析:https://blog.csdn.net/zhxdick/article/details/119990463
SpringRedisTemplate针对这个Scan进行了封装,示例使用(针对最新库spring-data-redis-1.8.1.RELEASE):
Set<Object> execute = redisTemplate.execute(new RedisCallback<Set<Object>>() {
@Override
public Set<Object> doInRedis(RedisConnection connection) throws DataAccessException {
Set<Object> binaryKeys = new HashSet<>();
Cursor<byte[]> cursor = connection.scan( new ScanOptions.ScanOptionsBuilder().match("test*").count(1000).build());
while (cursor.hasNext()) {
binaryKeys.add(new String(cursor.next()));
}
return binaryKeys;
}
});
注意Cursor一定不能关闭,在之前的版本中,这里Cursor需要手动关闭,但是从1.8.0开始,不能手动关闭!否则会报异常。
ScanOptions有两个参数,一个是match,另一个是count,分别对应scan命令的两个参数。
Scan命令源码:
/* Handle the case of a hash table. */ ht = NULL; if (o == NULL) {//键扫描 ht = c->db->dict; } else if (o->type == REDIS_SET && o->encoding == REDIS_ENCODING_HT) { ht = o->ptr; } else if (o->type == REDIS_HASH && o->encoding == REDIS_ENCODING_HT) { ht = o->ptr; count *= 2; /* We return key / value for this type. */ } else if (o->type == REDIS_ZSET && o->encoding == REDIS_ENCODING_SKIPLIST) { zset *zs = o->ptr; ht = zs->dict; count *= 2; /* We return key / value for this type. */ } //由于redis的ziplist, intset等类型数据量挺少,所以可用一次返回的。下面的else if 做这个事情。全部返回一个key 。 if (ht) {//一般的存储,不是intset, ziplist void *privdata[2]; /* We pass two pointers to the callback: the list to which it will * add new elements, and the object containing the dictionary so that * it is possible to fetch more data in a type-dependent way. */ privdata[0] = keys; privdata[1] = o; do { //一个个扫描,从cursor开始,然后调用回调函数将数据设置到keys返回数据集里面。 cursor = dictScan(ht, cursor, scanCallback, privdata); } while (cursor && listLength(keys) < count); } else if (o->type == REDIS_SET) { int pos = 0; int64_t ll; while(intsetGet(o->ptr,pos++,&ll))//将这个set里面的数据全部返回,因为它是压缩的intset,会很小的。 listAddNodeTail(keys,createStringObjectFromLongLong(ll)); cursor = 0; } else if (o->type == REDIS_HASH || o->type == REDIS_ZSET) {//那么一定是ziplist了,字符串表示的数据结构,不会太大。 unsigned char *p = ziplistIndex(o->ptr,0); unsigned char *vstr; unsigned int vlen; long long vll; while(p) {//扫描整个键,然后全部返回这一条。并且返回cursor为0表示没东西了。其实这个就等于没有遍历 ziplistGet(p,&vstr,&vlen,&vll); listAddNodeTail(keys, (vstr != NULL) ? createStringObject((char*)vstr,vlen) : createStringObjectFromLongLong(vll)); p = ziplistNext(o->ptr,p); } cursor = 0; } else { redisPanic("Not handled encoding in SCAN."); }
可以看出,Redis的SCAN操作由于其整体的数据设计,无法提供特别准的scan操作,仅仅是一个“can ‘ t guarantee , just do my best”的实现:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。