keys指令和scan指令
@Test
public void testScan() {
Set keys = jedis.keys("*");
System.out.println(keys.toString());
int count = 3;
ScanParams scanParams = new ScanParams();
ScanResult scan = jedis.scan("0", scanParams.count(count).match("*"));
List list = new ArrayList<>(scan.getResult());
for (;
;
) {
String stringCursor = scan.getStringCursor();
//当游标为0时说明遍历完成,退出循环
if (stringCursor.equals("0")) {break;
} else {
scan = jedis.scan(stringCursor, scanParams.count(count).match("*"));
System.out.println("---"+scan.getResult().toString());
list.addAll(scan.getResult());
}
}
System.out.println(list.toString());
//jedis.scan("0");
//jedis.hscan("myHash", "0");
}
1 keys命令 可以使用正则查找匹配的结果。
该命令有致命的缺点:
- 没有limit,只能一次性获取所有符合条件的key。如果数据量很大的话,就会产生无穷无尽的输出。
- keys命令是遍历算法,遍历全部的key,时间复杂度是O(N)。redis是单线程的,如果keys查询的时间过长,redis的其它操作会被阻塞较长时间,造成redis较长时间的卡顿。要避免在生产环境使用该命令。
cursor = 0时表示开始查询,第一次查询。每次查询结果中都会返回一个cursor,作为下次查询的开始游标。当某次查询返回的cursor=0时,表示已全部查询完毕。
相比于keys命令,scan命令有两个比较明显的优势:
- scan命令的时间复杂度虽然也是O(N),但它是分次进行的,不会阻塞线程。
- scan命令提供了limit参数,可以控制每次返回结果的最大条数。
返回的数据有可能重复,需要我们在业务层按需要去重
Redis中的Pipeline Redis的管道可以在大量数据需要一次性操作完成的时候,使用Pipeline进行批处理,将一大队的操作合并成一次操作,可以减少链路层的时间消耗,毕竟频繁操作是不好的嘛.
@Test
public void pipeCompare() {
Jedis redis = jedis;
//redis.auth("12345678");
//授权密码 对应redis.conf的requirepass密码
Map data = https://www.it610.com/article/new HashMap();
redis.select(8);
//使用第8个库
redis.flushDB();
//清空第8个库所有数据
// hmset
long start = System.currentTimeMillis();
// 直接hmset
for (int i = 0;
i < 10000;
i++) {
data.clear();
//清空map
data.put("k_" + i, "v_" + i);
redis.hmset("key_" + i, data);
//循环执行10000条数据插入redis
}
long end = System.currentTimeMillis();
System.out.println("共插入:[" + redis.dbSize() + "]条 .. ");
System.out.println("1,未使用PIPE批量设值耗时" + (end - start)+ "毫秒..");
redis.select(8);
redis.flushDB();
// 使用pipeline hmset
Pipeline pipe = redis.pipelined();
start = System.currentTimeMillis();
//
for (int i = 0;
i < 10000;
i++) {
data.clear();
data.put("k_" + i, "v_" + i);
pipe.hmset("key_" + i, data);
//将值封装到PIPE对象,此时并未执行,还停留在客户端
}
pipe.sync();
//将封装后的PIPE一次性发给redis
end = System.currentTimeMillis();
System.out.println("PIPE共插入:[" + redis.dbSize() + "]条 .. ");
System.out.println("2,使用PIPE批量设值耗时" + (end - start)+ "毫秒 ..");
//--------------------------------------------------------------------------------------------------
// hmget
Set keys = redis.keys("key_*");
//将上面设值所有结果键查询出来
// 直接使用Jedis hgetall
start = System.currentTimeMillis();
Map> result = new HashMap>();
for (String key : keys) {
//此处keys根据以上的设值结果,共有10000个,循环10000次
result.put(key, redis.hgetAll(key));
//使用redis对象根据键值去取值,将结果放入result对象
}
end = System.currentTimeMillis();
System.out.println("共取值:[" + redis.dbSize() + "]条 .. ");
System.out.println("3,未使用PIPE批量取值耗时 " + (end - start)+ "毫秒..");
// 使用pipeline hgetall
result.clear();
start = System.currentTimeMillis();
for (String key : keys) {
pipe.hgetAll(key);
//使用PIPE封装需要取值的key,此时还停留在客户端,并未真正执行查询请求
}
pipe.sync();
//提交到redis进行查询end = System.currentTimeMillis();
System.out.println("PIPE共取值:[" + redis.dbSize() + "]条 .. ");
System.out.println("4,使用PIPE批量取值耗时" + (end - start)+ "毫秒 ..");
redis.disconnect();
}
pipeline注意点
- pipeline只适用于那些不需要获取同步结果的场景,比如hincr,hset等更新操作。而对于读取hget操作则不能适用。
- pipeline组装命令也不能是没有节制的,如果pipeline组装命令数据过多,则会导致一次pipeline同步等待时间过长,影响客户端体验甚至导致网络阻塞。
- pipeline不能保证命令执行的原子性。如多个命令在执行的中间发生了异常,那么将会丢失未执行的命令。所以我们一般使用pipeline时,需要自己保证执行命令的数据安全性。
推荐阅读
- Redis|redis原理之布隆过滤器(Bloom Filter)
- redis安装与基本使用
- java|图解四种 IO 模型
- Redis|Redis性能解析--Redis为什么那么快()
- java|你跳一次涨多少(今天见识到跳槽天花板!!)
- java|送你一份大厂都这么解决Redis缓存问题,面试官必问!
- (免费领取红包封面)【Redis 系列】redis 学习四,set 集合,hash 哈希,zset 有序集合初步认知
- redis优化(bigkey、hotkey)
- redis高可用(主从、哨兵、集群)
- 【Redis 系列】redis 学习四,set 集合,hash 哈希,zset 有序集合初步认知