redis系列
序
在redis的db存在大量key或者db里头的某个set、zset、hash里头的元素非常多的话,用普通的get all操作很可能导致redis因为这个操作阻塞了,导致不能响应其他操作,特别是在高并发、海量数据的背景下,这个问题显得尤其严重。那么能不能像数据库那样有个分页的功能呢,答案就是scan操作。本文主要展示怎么在redis-cli以及SpringDataRedis中的使用。
scan语法
scan之后返回两部分,第一部分是下次scan的参数,第二部分就是scan出来的项
作用对象(db、set、zset、hash)
- db(
key
)
127.0.0.1:6379> scan 0
1) "120"
2) 1) "articleMap:63"
2) "articleMap:37"
3) "counter:__rand_int__"
4) "articleMap:60"
5) "tagSet:tag5"
6) "articleMap:80"
7) "messageCache~keys"
8) "mymap"
9) "articleMap:46"
10) "articleMap:55"
127.0.0.1:6379> scan 120
1) "28"
2) 1) "articleMap:17"
2) "tagSet:tag1"
3) "articleMap:18"
4) "articleMap:81"
5) "\xac\xed\x00\x05t\x00\btest-cas"
6) "articleMap:51"
7) "articleMap:94"
8) "articleMap:26"
9) "articleMap:71"
10) "user-abcde"
- set(
value
)
127.0.0.1:6379> sscan myset 0
1) "3"
2) 1) "m"
2) "j"
3) "c"
4) "h"
5) "f"
6) "i"
7) "a"
8) "g"
9) "n"
10) "e"
11) "b"
127.0.0.1:6379> sscan myset 3
1) "0"
2) 1) "l"
2) "k"
3) "d"
- zset(
value & score
)
127.0.0.1:6379> zscan sortset 0
1) "0"
2) 1) "tom"
2) "89"
3) "jim"
4) "90"
5) "david"
6) "100"
- hash(
key & value
)
127.0.0.1:6379> hscan mymap 0
1) "0"
2) 1) "name"
2) "codecraft"
3) "email"
4) "pt@g.cn"
5) "age"
6) "20"
7) "desc"
8) "hello"
9) "sex"
10) "male"
SCAN的额外参数
- count(
指定每次取多少条
)
127.0.0.1:6379> scan 0 count 5
1) "240"
2) 1) "articleMap:63"
2) "articleMap:37"
3) "counter:__rand_int__"
4) "articleMap:60"
5) "tagSet:tag5"
- match(
匹配key
)
127.0.0.1:6379> scan 0 match article*
1) "120"
2) 1) "articleMap:63"
2) "articleMap:37"
3) "articleMap:60"
4) "articleMap:80"
5) "articleMap:46"
6) "articleMap:55"
RedisTemplate操作
遍历数据库key
@Test
public void scanDbKeys(){
template.execute(new RedisCallback<Iterable<byte[]>>() {
@Override
public Iterable<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
List<byte[]> binaryKeys = new ArrayList<byte[]>();
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().count(5).build());
while (cursor.hasNext()) {
byte[] key = cursor.next();
binaryKeys.add(key);
System.out.println(new String(key, StandardCharsets.UTF_8));
}
try {
cursor.close();
} catch (IOException e) {
// do something meaningful
}
return binaryKeys;
}
});
}
遍历set
/**
* sadd myset a b c d e f g h i j k l m n
*/
@Test
public void scanSet(){
Cursor<String> cursor = template.opsForSet().scan("myset",ScanOptions.NONE);
while (cursor.hasNext()){
System.out.println(cursor.next());
}
}
遍历zset
/**
* zadd sortset 89 tom 90 jim 100 david
*/
@Test
public void scanZSet(){
Cursor<ZSetOperations.TypedTuple<String>> cursor = template.opsForZSet().scan("sortset",ScanOptions.NONE);
while (cursor.hasNext()){
ZSetOperations.TypedTuple<String> item = cursor.next();
System.out.println(item.getValue() + ":" + item.getScore());
}
}
遍历hash
/**
* hset mymap name "codecraft"
* hset mymap email "pt@g.cn"
* hset mymap age 20
* hset mymap desc "hello"
* hset mymap sex "male"
*/
@Test
public void scanHash(){
Cursor<Map.Entry<Object, Object>> curosr = template.opsForHash().scan("mymap", ScanOptions.NONE);
while(curosr.hasNext()){
Map.Entry<Object, Object> entry = curosr.next();
System.out.println(entry.getKey()+":"+entry.getValue());
}
}