sscan、scan、smembers 的区别及应用场景

本文主要介绍 scan、sscan 、smembers 的区别及在工作中的实际运用场景。

scan 和 sscan

适用范围

  • scan:用于执行 redis 的通用扫描命令,可以用于迭代遍历任何类型的键;
  • sscan:用于执行 redis 的集合扫描命令,专门用于迭代遍历集合类型的键

参数

  • scan:接受游标、匹配模式和返回数量等参数,可以更灵活地控制迭代过程;
  • sscan:接受集合键、游标和扫描参数等参数,用于迭代遍历指定集合中的成员。

返回值

  • scan:返回的是一个包含游标和键列表的结果集;
  • sscan:返回的是一个包含游标和成员列表的结果集。

使用场景

  • scan:适用于需要迭代遍历大量键或按照特定模式匹配键的情况;
  • sscan:适用于需要迭代遍历特定集合中的成员的情况。

scan案例

假设我们有一个 redis 数据库,其中包含多个以 “user:” 开头的键,每个键代表一个用户的信息。我们想要获取所有以 “user:” 开头的键,并打印它们的值。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

public class RedisScannerExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);

        try {
            // 设置匹配模式为以 "user:" 开头的键
            String pattern = "user:*";
            
            // 设置每次迭代返回的最大数量为 10
            int pageSize = 10;

            // 设置初始游标为 "0"
            String cursor = ScanParams.SCAN_POINTER_START;

            // 创建 ScanParams 对象,并设置匹配模式和每次迭代返回的最大数量
            ScanParams params = new ScanParams().match(pattern).count(pageSize);

            // 开始迭代扫描
            do {
                // 执行 SCAN 命令
                ScanResult<String> result = jedis.scan(cursor, params);

                // 获取当前迭代返回的键列表
                for (String key : result.getResult()) {
                    // 打印键和对应的值
                    System.out.println("Key: " + key + ", Value: " + jedis.get(key));
                }

                // 更新游标
                cursor = result.getStringCursor();
            } while (!cursor.equals(ScanParams.SCAN_POINTER_START));
        } finally {
            // 关闭连接
            jedis.close();
        }
    }
}

sscan 案例

假设我们有一个 redis 集合,其中存储了一组用户的 ID,我们想要获取该集合中的所有用户 ID。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

public class RedisSScanExample {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);

        try {
            // 集合的键
            String key = "user_ids";

            // 设置初始游标为 "0"
            String cursor = ScanParams.SCAN_POINTER_START;

            // 创建 ScanParams 对象,设置每次迭代返回的最大数量
            ScanParams params = new ScanParams().count(10);

            // 开始迭代扫描集合
            do {
                // 执行 SSCAN 命令
                ScanResult<String> result = jedis.sscan(key, cursor, params);

                // 获取当前迭代返回的成员列表
                for (String member : result.getResult()) {
                    // 打印成员
                    System.out.println("Member: " + member);
                }

                // 更新游标
                cursor = result.getStringCursor();
            } while (!cursor.equals(ScanParams.SCAN_POINTER_START));
        } finally {
            // 关闭连接
            jedis.close();
        }
    }
}

sscan和smembers

sscan 和 smembers 是 redis 中用于操作集合的两个命令,区别如下:

返回方式

  • sscan:以迭代器的方式返回集合中的元素,每次调用返回一批元素;
  • smembers:一次性的返回集合中所有元素。

使用场景

  • SSCAN:适用于大型集合,因为它可以分批返回元素,不会因为集合大小而造成阻塞或占用大量内存;
  • SMEMBERS:适用于小型集合,因为它一次性返回所有元素,适用于集合元素数量较少的情况。

性能

  • SSCAN:由于以迭代器方式返回元素,可以在大型集合中实现高性能的迭代操作;
  • SMEMBERS:性能相对较差,尤其在大型集合中,因为它需要一次性返回所有元素。

smembers案例

假设我们有一个 redis 集合,其中存储了一组用户的 ID,我们想要获取该集合中的所有用户 ID。

import redis.clients.jedis.Jedis;
import java.util.Set;

public class RedisSMEMBERSExample {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        try {
            // 集合的键
            String key = "user_ids";
            // 获取集合中的所有成员
            Set<String> members = jedis.smembers(key);
            // 打印集合中的所有成员
            for (String member : members) {
                System.out.println("Member: " + member);
            }
        } finally {
            // 关闭连接
            jedis.close();
        }
    }
}

线上使用

在【redis 使用场景一】文章中提到的,使用 redis 缓存来构建本地缓存,在test_user_data集合中大约保存了 50 多万的用户 id,所以用的 sscan

public Set<String> sscanAll(String keyPattern, int pageSize) {
        try {
            Set<String> result = new HashSet<>();
            String envPattern = prefixKey + keyPattern;
            ScanParams scanParams = new ScanParams();
            scanParams.count(pageSize);
            String cursor = ScanParams.SCAN_POINTER_START;
            while(true){
                ScanResult scanResult = jedisCluster.sscan(envPattern, cursor, scanParams);
                List<String> currentPage = scanResult.getResult();
                cursor = scanResult.getStringCursor();
                result.addAll(currentPage);

                if("0".equals(cursor)){
                    break;
                }
            }

            return result;
        } catch (Exception e) {
            throw e;
        }
    }

    public Set<String> sscanAll(String keyPattern){
        return sscanAll(keyPattern, 1000);
    }

总结

smembers、sscan、scan 各有适用场景,应根据集合大小、内存限制和性能要求来选择最合适的命令。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值