集群模式下RedisTemplate使用Scan命令全节点模糊匹配key

为什么需要模糊匹配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;
    }

在Java中,RedisTemplate类提供了scan方法来进行Redis的扫描操作。这个方法可以通过指定匹配模式来获取与模式匹配的键集合。使用scan方法可以避免使用keys命令Redis进行扫描时可能导致的性能问题。 下面是一个示例代码,展示了如何使用RedisTemplate的scan方法来进行Redis的扫描操作: ```java public static Set<String> scan(RedisTemplate<String, Object> redisTemplate, String pattern) { return redisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<String> keysTmp = new HashSet<>(); try (Cursor<byte[]> cursor = connection.scan( new ScanOptions.ScanOptionsBuilder() .match(pattern) .count(10000).build())) { while (cursor.hasNext()) { keysTmp.add(new String(cursor.next(), "Utf-8")); } } catch (Exception e) { logger.error(e.getMessage(), e); throw new RuntimeException(e); } return keysTmp; }); } ``` 以上代码是一个RedisHelper类的一个静态方法,该方法接收一个RedisTemplate对象和一个匹配模式作为参数,然后使用scan方法进行扫描,并返回与模式匹配的键集合。 需要注意的是,scan方法是一个非阻塞的操作,并且可以按照预先设定的页数多次从Redis中进行查找。因此,使用scan方法可以更高效地获取与模式匹配的键集合,并且可以避免影响其他服务的使用。 希望这个例子对你有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [在 RedisTemplate使用 scan](https://blog.csdn.net/qq_38787653/article/details/128367121)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Java教程:RedisTemplate如何存取数据并使用scan非阻塞删除](https://blog.csdn.net/wfeil211/article/details/128134602)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值