为什么需要模糊匹配key?
因为有时候,缓存的key设计的不合理,比如商品信息的缓存设计成:门店编码+商品id,
当我们需要查询一个门店下的所有商品缓存的时候,可能就需要获取这个门店编码下的所有商品信
息的key然后遍历获取门店下的所有商品。
为什么使用Scan?
因为Keys是阻塞的,严重影响性能,官方不建议生产环境使用,取而代之的是Scan命令。
Scan命令怎么使用呢?
语法: scan cursor [MATCH pattern] [COUNT count]
语法说明:[]里面的代表可选可不选
scan :命令关键字
cursor :起始下标
MATCH pattern:MATCH是关键字全大写, pattern是要模糊匹配的正则表达式 默认是*
COUNT count:COUNT是关键字全大写,count是模糊匹配的数量 默认是10
比如 :
- scan 0 :从0下标开始全匹配
- scan 0 MATCH ab* :从0下标开始10个key,匹配其中找到ab开头的key
- scan 0 MATCH ab* COUNT 100 :从0下标开始100个key,匹配其中找到ab开头的key
Redis支持的正则表达式:
? :代表任意字符
* :代表任意长度的字符
[] :代表[]中的任意一个字符,[abc]表示abc中的任意一个字符
比如我想模糊匹配下面的key:
1) "md:v2:pd:preSell:storeCodeAndSkuId[storeCode,skuId]:[0008,63168]"
2) "md:v2:pd:preSell:storeCodeAndSkuId[storeCode,skuId]:[0008,12685]"
3) "md:v2:pd:preSell:storeCodeAndSkuId[storeCode,skuId]:[0008,4632809]"
4) "md:v2:pd:preSell:storeCodeAndSkuId[storeCode,skuId]:[0008,4693253]"
命令如下
scan 0 MATCH md:v2:pd:preSell:storeCodeAndSkuId?storeCode,skuId?:?0008,*? COUNT 100000
scan 命令返回的是个数组,数组的第一个值是scan到的cursor位置,第二个值就是匹配的key的数组,第一个值每次返回的值可能看起来有点奇怪,建议参考深入理解Redis的scan命令
Scan命令的限制?
scan命令只能在一个Redis节点上遍历,如果是集群的话,他并不能遍历所有Redis节点
怎么用Scan命令遍历通过RedisTemplate遍历所有Redis集群里的节点呢?
public static Set<String> scanMatch(String matchKey) {
Set<String> keys = new HashSet();
RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
RedisClusterConnection clusterConnection = connectionFactory.getClusterConnection();
Iterable<RedisClusterNode> redisClusterNodes = clusterConnection.clusterGetNodes();
Iterator<RedisClusterNode> iterator = redisClusterNodes.iterator();
while (iterator.hasNext()) {
RedisClusterNode next = iterator.next();
Cursor<byte[]> scan = clusterConnection.scan(next, ScanOptions.scanOptions().match(matchKey).count(10000000).build());
while (scan.hasNext()) {
keys.add(new String(scan.next()));
}
}
return keys;
}