• 详解Redis基础数据类型Set增删查(带Java源码)


    1 缘起

    继续补充Redis基础数据集合操作,
    从高中开始,我们就已经学习了集合,
    常考的概念有:交集、并集和补集等,
    因此,Redis的集合操作同样有这些操作,
    当业务有使用集合的只交并补时,可使用set。
    文章帮助读者系统性掌握set相关,
    轻松应对知识考核与交流。

    为帮助读者更加系统地学习Redis基础数据操作,
    分享其他数据类型操作文章:

    Redis进阶:图文讲解Redis底层数据结构之embstr,raw,ziplist,quicklist和hashtable (带源码讲解)

    注意:

    (1)文末附全部测试代码;
    (2)本篇文章将学习使用如下函数(方法):

    序号操作method
    1新增sadd
    2删除srem
    3集合操作sdiff,sinter,sunion
    4查询smembers,sismember

    2 Set测试

    Redis基础数据类型Set代表存储的值(value)为集合。
    本文采用连接池的方式直连Redis,连接池配置如下:

    • 依赖
    
    <dependency>
        <groupId>redis.clientsgroupId>
        <artifactId>jedisartifactId>
        <version>3.5.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • Redis连接池配置(可以根据需要设置为共用)
    private static JedisPool getJedisPool() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // Jedis池:最大连接数
            jedisPoolConfig.setMaxTotal(1);
            // Jedis池:最大空闲连接数
            jedisPoolConfig.setMaxIdle(10);
            // Jedis池:等待时间
            jedisPoolConfig.setMaxWaitMillis(3000);
            // Jedis池:连接Redis超时时间
            int connectTimeout = 2000;
            String redisHost = "127.0.0.1";
            int redisPort = 6379;
            String redisPassword = "123456";
            int redisDb = 0;
            // 创建连接池
            return new JedisPool(jedisPoolConfig, redisHost, redisPort, connectTimeout, redisPassword, redisDb);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.1 新增数据:add

    集合同样初始化,因此,有了新增数据操作,
    测试样例如下,根据集合数据的特性,新增数据是按照批量新增设计的。

    /**
         * 新增数据.
         */
        @Test
        public void insertData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 批量添加
                Long res1 = jedis.sadd("nameset-1", "xiaoyi", "xiaoer", "xiaosan");
                Long res2 = jedis.sadd("nameset-2", "xiaoyi", "xiaoer", "xiaosi");
                logger.info(">>>>>>>Set插入数据:{}, {}", res1, res2);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set插入数据异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    新增数据源码如下图所示,
    由注释可知,新增数据时,如果集合中已存在数据,则不操作(不会修改集合数据),
    时间复杂度:O(1)。
    在这里插入图片描述

    2.2 删除数据:srem

    set的删除数据同样是按照批量数据删除设计的,
    测试杨样例如下:

    /**
         * 删除数据.
         */
        @Test
        public void deleteData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 批量删除
                Long res1 = jedis.srem("nameset", "xiaoyi", "xiaoer");
                logger.info(">>>>>>>Set删除数据:{}", res1);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set删除异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    删除数据源码如下图所示,
    由注释可知,当删除的数据不存在时不操作集合,
    如果删除的键没有对应的集合,则返回错误,
    时间复杂度为:O(1)。
    在这里插入图片描述

    2.3 集合操作

    集合操作,最常用的即为上文提到的:交集、并集和补集(差集),
    测试样例如下:

    /**
         * 集合操作.
         * sdiff:差集
         * sinter:交集
         * sunion:并集
         */
        @Test
        public void diffAndInterData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 差集
                Set<String> res1 = jedis.sdiff("nameset-1", "nameset-2");
                // 交集
                Set<String> res2 = jedis.sinter("nameset-1", "nameset-2");
                // 并集
                Set<String> res3 = jedis.sunion("nameset-1", "nameset-2");
                logger.info(">>>>>>>>>>Set差集,交集,并集:{}, {}, {}", res1, res2, res3);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set操作异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.3.1 sdiff

    多个集合取差集源码如下,
    由注释可知,该方法返回多个集合的差集,
    时间复杂度:O(n)。
    在这里插入图片描述

    2.3.2 sinter

    多个集合的交集源码如下图所示,
    由注释可知,返回多个结合的交集,
    时间复杂度为:O(N*M),其中,N为最小集合数据量,M为集合个数。
    在这里插入图片描述

    2.3.3 sunion

    多个集合取并集源码如下图所示,
    由注释可知,时间复杂度:O(N),
    其中,N为所有结合的数据总和。
    在这里插入图片描述

    2.4 查询数据

    结合查询数据有两种情况,即
    (1)查询结合所有数据;
    (2)查询某个数据是否在集合;
    测试样例如下:

    /**
         * 查询数据.
         */
        @Test
        public void queryData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 查询某个集合所有数据
                Set<String> res1 = jedis.smembers("nameset-1");
                // 判断某数据是否在集合
                Boolean res2 = jedis.sismember("nameset-1", "xiaoyi");
                logger.info(">>>>>>>Set查询:{},{}", res1, res2);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set查询数据异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.4.1 smembers

    查询集合的素有数据源码如下图所示,
    由注释可知,时间复杂度为:O(N)。
    在这里插入图片描述

    2.4.2 ismember

    判断某个元素是否属于指定集合源码如下图所示,
    由注释可知,时间复杂度为:O(1)。
    在这里插入图片描述

    3 小结

    Redis集合操作只有增删查,并没有更新操作,
    因此,向修改集合的数据,需要先删除数据,再新增,
    同时,集合有自身的特定功能,有交集、并集和补集(差集)操作。
    操作方法一览表如下:

    序号操作method
    1新增sadd
    2删除srem
    3集合操作sdiff,sinter,sunion
    4查询smembers,sismember

    为帮助读者更加系统地学习Redis基础数据操作,
    分享其他数据类型操作文章:

    Redis进阶:图文讲解Redis底层数据结构之embstr,raw,ziplist,quicklist和hashtable (带源码讲解)

    附件

    package database_test.redis_test;
    
    import org.junit.Test;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.Set;
    
    /**
     * set测试.
     *
     * @author xindaqi
     * @since 2022-08-18 18:03
     */
    public class SetTest {
    
        private static final Logger logger = LoggerFactory.getLogger(SetTest.class);
    
        private static JedisPool getJedisPool() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // Jedis池:最大连接数
            jedisPoolConfig.setMaxTotal(1);
            // Jedis池:最大空闲连接数
            jedisPoolConfig.setMaxIdle(10);
            // Jedis池:等待时间
            jedisPoolConfig.setMaxWaitMillis(3000);
            // Jedis池:连接Redis超时时间
            int connectTimeout = 2000;
            String redisHost = "127.0.0.1";
            int redisPort = 6379;
            String redisPassword = "123456";
            int redisDb = 0;
            // 创建连接池
            return new JedisPool(jedisPoolConfig, redisHost, redisPort, connectTimeout, redisPassword, redisDb);
        }
    
        /**
         * 新增数据.
         */
        @Test
        public void insertData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 批量添加
                Long res1 = jedis.sadd("nameset-1", "xiaoyi", "xiaoer", "xiaosan");
                Long res2 = jedis.sadd("nameset-2", "xiaoyi", "xiaoer", "xiaosi");
                logger.info(">>>>>>>Set插入数据:{}, {}", res1, res2);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set插入数据异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
        /**
         * 删除数据.
         */
        @Test
        public void deleteData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 批量删除
                Long res1 = jedis.srem("nameset", "xiaoyi", "xiaoer");
                logger.info(">>>>>>>Set删除数据:{}", res1);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set删除异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
        /**
         * 集合操作.
         * sdiff:差集
         * sinter:交集
         * sunion:并集
         */
        @Test
        public void diffAndInterData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 差集
                Set<String> res1 = jedis.sdiff("nameset-1", "nameset-2");
                // 交集
                Set<String> res2 = jedis.sinter("nameset-1", "nameset-2");
                // 并集
                Set<String> res3 = jedis.sunion("nameset-1", "nameset-2");
                logger.info(">>>>>>>>>>Set差集,交集,并集:{}, {}, {}", res1, res2, res3);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set操作异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    
        /**
         * 查询数据.
         */
        @Test
        public void queryData() {
            try (Jedis jedis = getJedisPool().getResource()) {
                // 查询某个集合所有数据
                Set<String> res1 = jedis.smembers("nameset-1");
                // 判断某数据是否在集合
                Boolean res2 = jedis.sismember("nameset-1", "xiaoyi");
                logger.info(">>>>>>>Set查询:{},{}", res1, res2);
            } catch (Exception ex) {
                logger.error(">>>>>>>>Redis set查询数据异常:", ex);
                throw new RuntimeException(ex);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
  • 相关阅读:
    【html】面试问题总结
    GPT 的基础 - T(Transformer)
    湖仓一体电商项目(十一):编写写入DWS层业务代码
    Unity6 URP17使用初探
    leetcode 58
    SwiftUI Spacer() onTapGesture 无法触发
    Spring boot 配置文件
    windows下-mysql环境配置,以及使用navicat可视化数据库,便捷撰写sql语句。
    GC 算法与种类
    java基本数据类型
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/126806101