Spring RedisTemplate实现scan操作

老生常谈,keys不安全,因为

  • keys的操作会导致数据库暂时被锁住,其他的请求都会被堵塞;业务量大的时候会出问题

Spring RedisTemplate实现scan

1. hscan sscan zscan

  • 例子中的"field"是值redis的key,即从key为"field"中的hash中查找
  • redisTemplate的opsForHash,opsForSet,opsForZSet 可以 分别对应 sscan、hscan、zscan
  • 也可以使用 (JedisCommands) connection.getNativeConnection() 的 hscan、sscan、zscan 方法实现cursor遍历,参照下文2.2章节
try {
    Cursor<Map.Entry<Object,Object>> cursor = redisTemplate.opsForHash().scan("field",
    ScanOptions.scanOptions().match("*").count(1000).build());
    while (cursor.hasNext()) {
        Map.Entry<Object,Object> entry = cursor.next();
        Object key = entry.getKey();
        Object valueSet = entry.getValue();
    }
    //关闭cursor
    cursor.close();
} catch (IOException e) {
    e.printStackTrace();
}

 

  • cursor.close(); 游标一定要关闭,不然连接会一直增长;可以使用client lists info clients info stats 命令查看客户端连接状态,会发现scan操作一直存在
  • 我们平时使用的redisTemplate.execute 是会主动释放连接的,可以查看源码确认
  • 代码虽然只是调用一次scan方法,但是spring-data-redis已经对scan做了封装,这个scan结合cursor.hasNext会多次redis scan,最终拿到所有match的结果

2. scan

2.1 使用spring-data-redis封装好的scan方法

    public Set<String> scan(String matchKey) {
        Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keysTmp = new HashSet<>();
            Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
                            .match("*" + matchKey + "*").count(1000).build()); while (cursor.hasNext()) { keysTmp.add(new String(cursor.next())); } return keysTmp; }); return keys; }

 

  项目中我用的就是这种方法来代替 

Set keys = redisTemplate.keys(uploadTag + entity.getCaseNo() + ":*");

 

  

posted @ 2021-11-18 18:42  佩洛君  阅读(9409)  评论(0编辑  收藏  举报