redis的scan的使用

1.scan命令

在有些场景中,我们希望去查找符合部分字符匹配的key,
在scan命令出来之前,都是使用keys命令 ,keys pattern,这种命令严禁在线上环境中使用,因为keys命令会去匹配所有的key,与之类似的可能阻塞服务的命令还有smebmers,hgetall,如果hash和set中元素较多,由于redis的单线程的机制,这些类似的命令都可能阻塞redis服务。
在这样的背景下,scan命令诞生了,

SCAN cursor [MATCH pattern] [COUNT count]

scan 命令调用完后每次会返回2个元素,第一个是下一次迭代的cursor,第一次cursor会设置为0,当最后一次scan 返回的cursor等于0时,表示整个scan遍历结束了,第二个返回的是List,一个匹配的key的数组。

cursor: :我们知道redis是key:value形式的,所以在外层的数据结构,很容易让我们联想到hashMap类似的数据接口,hashMap最基本的形式是采用数组加链表的形式进行存贮的,而cursor就是最外的一维数组的索引,第一次使用scan,cursor设置为0, 第二cursor设置成第一次返回cursor的值,如果cursor返回是0,表示迭代完毕。
match pattern: pattern支持redis的通配符,例如 * 表示匹配任意个字符,?匹配一个字符

count: 表示查找多少个数组元素,把匹配的结果,加入到返回的结果集中,count默认是10,可以根据实际需求自由的调整。

2. Jedis操作scan

Jedis jedis = new Jedis("127.0.0.1",6379);

		for(int i =0;i<20000;i++){
			jedis.set("20200606:"+i,i+"","NX","EX",600);
		}

		for(int i =20000;i<40000;i++){
			jedis.hset("hash:20200606:"+i,i+"",i+"");
			jedis.expire("hash:20200606:"+i,600);
		}


		String cursor = "0";
		ScanParams params = new ScanParams();
		params.count(1000);
		params.match("*20200606*");
		int count = 0;
		do{
			ScanResult<String> result = jedis.scan(cursor,params);
			System.out.println(result.getResult());
			if(result.getResult() != null){
				count += result.getResult().size();
			}
			cursor = result.getStringCursor();
		}while (!cursor.equals("0"));

		System.out.println("total size is " + count);

hscan ,sscan,zscan 都是类似,只是需要指定特定的key,迭代的是相关的内部的元素。

3.scan存在问题

scan命令从开始到结束一个完整的迭代,可能会返回重复的元素,(如果hash表缩容的话),scan命令相对于keys命令不会阻塞redis服务器,如果要查某些部分字符匹配的key,用scan是很合适的。但是scan返回的不一定是此刻返回的所有匹配的结果,可能多,也可能少,因为整个数据可能在不断的变化,而唯一有状态的是cursor。

你可能感兴趣的:(redis)