写在前面List和Set是Redis中处理序列和集合数据的利器。List的队列特性让它成为消息队列的首选而Set的集合运算能力让社交功能开发变得简单。今天我们深入探讨这两种类型的实战技巧。文章目录写在前面一、List命令详解1.1 List的特点与底层实现1.2 插入命令1.3 弹出命令1.4 查询命令1.5 修改命令二、List应用场景2.1 消息队列2.2 最新列表2.3 时间线/动态2.4 分页查询三、Set命令详解3.1 Set的特点与底层实现3.2 基础操作命令3.3 随机操作命令3.4 集合运算命令3.5 迭代命令四、Set应用场景4.1 标签系统4.2 共同好友/共同关注4.3 唯一性判断4.4 抽奖系统4.5 社交推荐五、踩坑提醒List阻塞操作5.1 BLPOP/BRPOP注意事项5.2 大列表操作5.3 大集合操作六、List与Set对比6.1 功能对比6.2 场景选择七、面试高频考点Q1List如何实现消息队列Q2Set的集合运算时间复杂度是多少Q3如何实现一个简单的抽奖系统八、参考资料九、互动话题一、List命令详解1.1 List的特点与底层实现实际场景List就像一个可以两头操作的管道非常适合做队列和栈。List是Redis的列表类型具有以下特点有序元素按插入顺序排列可重复允许重复元素双向操作支持左右两端插入和弹出底层实现元素少时使用ziplist压缩列表元素多时使用quicklist双向链表ziplist1.2 插入命令# 左侧插入头部 lpush queue:task task1 # 左侧插入多个元素 lpush queue:task task2 task3 task4 # 右侧插入尾部 rpush queue:task task5 # 右侧插入多个元素 rpush queue:task task6 task7 # 在指定元素前插入 linsert queue:task before task3 task2.5 # 在指定元素后插入 linsert queue:task after task3 task3.5注意事项LPUSH/RPUSH可以一次插入多个元素LINSERT需要遍历列表时间复杂度O(n)1.3 弹出命令# 左侧弹出 lpop queue:task # 右侧弹出 rpop queue:task # 阻塞式左侧弹出等待30秒 blpop queue:task 30 # 阻塞式右侧弹出等待30秒 brpop queue:task 30 # 弹出并插入到另一个列表 rpoplpush queue:task queue:backup # 阻塞式弹出并插入 brpoplpush queue:task queue:backup 30注意事项LPOP/RPOP如果列表为空返回nilBLPOP/BRPOP是阻塞操作会一直等待直到有元素或超时RPOPLPUSH常用于消息队列的可靠性处理1.4 查询命令# 获取列表长度 llen queue:task # 获取指定范围元素0到-1表示全部 lrange queue:task 0 -1 # 获取前3个元素 lrange queue:task 0 2 # 获取最后3个元素 lrange queue:task -3 -1 # 通过索引获取元素 lindex queue:task 0 # 获取第一个元素 lindex queue:task 0 # 获取最后一个元素 lindex queue:task -11.5 修改命令# 设置指定索引的值 lset queue:task 0 new_task1 # 只保留指定范围的元素 ltrim queue:task 0 9 # 删除指定值的元素 lrem queue:task 1 task1LREM参数说明参数值说明count 0从头开始删除count个匹配元素count 0从尾开始删除count 0删除所有匹配元素二、List应用场景2.1 消息队列经验之谈List做消息队列简单可靠但功能有限。复杂场景建议用专业的消息中间件。# 生产者左侧插入消息 lpush queue:order order_data_1 # 消费者右侧阻塞弹出消息 brpop queue:order 30 # 可靠消费弹出并备份 brpoplpush queue:order queue:processing 30消息队列模式对比模式命令组合特点简单队列LPUSH RPOP先进先出栈模式LPUSH LPOP后进先出可靠队列LPUSH BRPOPLPUSH失败可恢复多消费者LPUSH BRPOP多个消费者竞争2.2 最新列表# 添加最新文章左侧插入 lpush latest:articles article:1001 # 只保留最新10篇 ltrim latest:articles 0 9 # 获取最新文章列表 lrange latest:articles 0 92.3 时间线/动态# 发布动态 lpush timeline:user:1001 post:2001 # 获取用户时间线 lrange timeline:user:1001 0 20 # 分页获取 lrange timeline:user:1001 0 9 # 第1页 lrange timeline:user:1001 10 19 # 第2页2.4 分页查询# 假设每页10条 # 第1页索引0-9 lrange list:data 0 9 # 第2页索引10-19 lrange list:data 10 19 # 第N页索引(N-1)*10 到 N*10-1 lrange list:data 20 29三、Set命令详解3.1 Set的特点与底层实现实际场景Set的去重和集合运算能力让社交功能开发变得简单。Set是Redis的集合类型具有以下特点无序元素没有固定顺序不重复自动去重支持集合运算交集、并集、差集底层实现元素少且都是整数时使用intset否则使用hashtable3.2 基础操作命令# 添加元素 sadd tags:article:1 redis database nosql # 添加单个元素 sadd tags:article:1 cache # 获取所有元素 smembers tags:article:1 # 检查元素是否存在 sismember tags:article:1 redis # 移除元素 srem tags:article:1 nosql # 获取集合大小 scard tags:article:13.3 随机操作命令# 随机获取一个元素不移除 srandmember tags:article:1 # 随机获取多个元素 srandmember tags:article:1 3 # 随机弹出元素移除 spop tags:article:1 # 随机弹出多个元素 spop tags:article:1 23.4 集合运算命令# 准备测试数据 sadd set:a 1 2 3 4 5 sadd set:b 3 4 5 6 7 sadd set:c 5 6 7 8 9 # 交集同时属于多个集合的元素 sinter set:a set:b # 返回3 4 5 # 并集所有集合的元素合并 sunion set:a set:b # 返回1 2 3 4 5 6 7 # 差集第一个集合有但其他集合没有的元素 sdiff set:a set:b # 返回1 2 # 交集并存储 sinterstore set:a_b set:a set:b # 并集并存储 sunionstore set:a_b_union set:a set:b # 差集并存储 sdiffstore set:a_b_diff set:a set:b集合运算图解运算说明命令交集A ∩ BSINTER并集A ∪ BSUNION差集A - BSDIFF3.5 迭代命令# 迭代获取元素适合大集合 sscan tags:article:1 0 match re* count 10四、Set应用场景4.1 标签系统实际场景文章标签、用户标签、商品标签Set都能轻松搞定。# 文章添加标签 sadd article:1001:tags redis database nosql # 获取文章所有标签 smembers article:1001:tags # 标签下的文章 sadd tag:redis:articles 1001 1002 1003 # 获取标签下的所有文章 smembers tag:redis:articles # 检查文章是否有某标签 sismember article:1001:tags redis4.2 共同好友/共同关注# 用户关注列表 sadd user:1001:following 1002 1003 1004 1005 sadd user:1002:following 1003 1004 1006 1007 # 共同关注 sinter user:1001:following user:1002:following # 返回1003 1004 # 我关注的人中谁关注了他 sinter user:1001:following user:1002:followers # 可能认识的人他关注但我没关注的人 sdiff user:1002:following user:1001:following # 返回1006 10074.3 唯一性判断# 投票去重 sadd vote:article:1001 user:1001 sadd vote:article:1001 user:1002 sadd vote:article:1001 user:1001 # 自动去重 # 检查是否已投票 sismember vote:article:1001 user:1001 # 获取投票人数 scard vote:article:1001 # 签到统计 sadd sign:20240101 user:1001 user:1002 user:1003 sadd sign:20240102 user:1001 user:1002 user:1004 # 连续签到用户 sinter sign:20240101 sign:202401024.4 抽奖系统# 添加抽奖用户 sadd lottery:20240101 user:1001 user:1002 user:1003 user:1004 user:1005 # 随机抽取1个中奖用户不移除 srandmember lottery:20240101 # 随机抽取3个中奖用户 srandmember lottery:20240101 3 # 抽取并移除不可重复中奖 spop lottery:202401014.5 社交推荐# 用户A的好友 sadd friends:a 1002 1003 1004 # 用户B的好友 sadd friends:b 1003 1004 1005 # 共同好友 sinter friends:a friends:b # 推荐好友B的好友中A不认识的人 sdiff friends:b friends:a五、踩坑提醒List阻塞操作踩坑提醒阻塞操作使用不当会导致连接超时或资源浪费5.1 BLPOP/BRPOP注意事项问题1长时间阻塞# 阻塞时间设置为0表示永久等待 blpop queue:task 0 # 危险可能导致连接永久挂起 # 建议设置合理的超时时间 blpop queue:task 30 # 30秒超时问题2多列表阻塞顺序# 按顺序检查列表返回第一个非空列表的元素 blpop queue:high queue:low 30 # 如果queue:high有元素优先返回问题3客户端断开阻塞期间客户端断开Redis会自动取消阻塞应用层需要处理重连逻辑5.2 大列表操作问题LRANGE获取大量元素# 危险获取全部元素可能阻塞Redis lrange big:list 0 -1 # 建议分批获取 lrange big:list 0 99 lrange big:list 100 199问题LREM删除大量元素# 删除所有匹配元素时间复杂度O(n) lrem big:list 0 value # 建议使用LTRIM或重建列表5.3 大集合操作问题SMEMBERS获取大量元素# 危险返回所有元素可能阻塞Redis smembers big:set # 建议使用SSCAN迭代获取 sscan big:set 0 count 100问题集合运算结果过大# 大集合交集可能很慢 sinter big:set:a big:set:b # 建议先计算小集合的交集再判断六、List与Set对比6.1 功能对比对比项ListSet有序性有序无序重复性可重复不重复随机访问支持LINDEX不支持范围查询支持LRANGE不支持集合运算不支持支持阻塞操作支持不支持6.2 场景选择场景推荐理由消息队列List支持阻塞弹出最新列表List有序支持范围查询分页List支持索引访问去重Set自动去重标签Set无需顺序支持集合运算共同好友Set支持交集运算抽奖Set支持随机获取七、面试高频考点Q1List如何实现消息队列答案简单队列LPUSH RPOP先进先出可靠队列LPUSH BRPOPLPUSH失败可恢复多消费者LPUSH BRPOP竞争消费注意事项消息持久化需要开启AOF或RDB消息确认需要业务层实现复杂场景建议用专业消息队列RabbitMQ、KafkaQ2Set的集合运算时间复杂度是多少答案SINTERO(N*M)N是最小集合大小M是集合数量SUNIONO(N)N是所有集合元素总数SDIFFO(N)N是所有集合元素总数优化建议先计算小集合使用SINTERSTORE缓存结果Q3如何实现一个简单的抽奖系统答案# 添加参与用户 sadd lottery:20240101 user:1001 user:1002 user:1003 # 抽取中奖者不可重复中奖 spop lottery:20240101 # 抽取多个中奖者 spop lottery:20240101 3 # 抽取中奖者可重复中奖 srandmember lottery:20240101八、参考资料Redis Set命令文档Redis数据结构详解九、互动话题你在项目中用List做过消息队列吗遇到过什么问题或者用Set实现过有趣的社交功能欢迎在评论区分享你的实战经验下一篇我们将深入探讨ZSet和Bitmap的高级用法。
【Redis】列表与集合Day4(2026年)
发布时间:2026/5/31 12:27:07
写在前面List和Set是Redis中处理序列和集合数据的利器。List的队列特性让它成为消息队列的首选而Set的集合运算能力让社交功能开发变得简单。今天我们深入探讨这两种类型的实战技巧。文章目录写在前面一、List命令详解1.1 List的特点与底层实现1.2 插入命令1.3 弹出命令1.4 查询命令1.5 修改命令二、List应用场景2.1 消息队列2.2 最新列表2.3 时间线/动态2.4 分页查询三、Set命令详解3.1 Set的特点与底层实现3.2 基础操作命令3.3 随机操作命令3.4 集合运算命令3.5 迭代命令四、Set应用场景4.1 标签系统4.2 共同好友/共同关注4.3 唯一性判断4.4 抽奖系统4.5 社交推荐五、踩坑提醒List阻塞操作5.1 BLPOP/BRPOP注意事项5.2 大列表操作5.3 大集合操作六、List与Set对比6.1 功能对比6.2 场景选择七、面试高频考点Q1List如何实现消息队列Q2Set的集合运算时间复杂度是多少Q3如何实现一个简单的抽奖系统八、参考资料九、互动话题一、List命令详解1.1 List的特点与底层实现实际场景List就像一个可以两头操作的管道非常适合做队列和栈。List是Redis的列表类型具有以下特点有序元素按插入顺序排列可重复允许重复元素双向操作支持左右两端插入和弹出底层实现元素少时使用ziplist压缩列表元素多时使用quicklist双向链表ziplist1.2 插入命令# 左侧插入头部 lpush queue:task task1 # 左侧插入多个元素 lpush queue:task task2 task3 task4 # 右侧插入尾部 rpush queue:task task5 # 右侧插入多个元素 rpush queue:task task6 task7 # 在指定元素前插入 linsert queue:task before task3 task2.5 # 在指定元素后插入 linsert queue:task after task3 task3.5注意事项LPUSH/RPUSH可以一次插入多个元素LINSERT需要遍历列表时间复杂度O(n)1.3 弹出命令# 左侧弹出 lpop queue:task # 右侧弹出 rpop queue:task # 阻塞式左侧弹出等待30秒 blpop queue:task 30 # 阻塞式右侧弹出等待30秒 brpop queue:task 30 # 弹出并插入到另一个列表 rpoplpush queue:task queue:backup # 阻塞式弹出并插入 brpoplpush queue:task queue:backup 30注意事项LPOP/RPOP如果列表为空返回nilBLPOP/BRPOP是阻塞操作会一直等待直到有元素或超时RPOPLPUSH常用于消息队列的可靠性处理1.4 查询命令# 获取列表长度 llen queue:task # 获取指定范围元素0到-1表示全部 lrange queue:task 0 -1 # 获取前3个元素 lrange queue:task 0 2 # 获取最后3个元素 lrange queue:task -3 -1 # 通过索引获取元素 lindex queue:task 0 # 获取第一个元素 lindex queue:task 0 # 获取最后一个元素 lindex queue:task -11.5 修改命令# 设置指定索引的值 lset queue:task 0 new_task1 # 只保留指定范围的元素 ltrim queue:task 0 9 # 删除指定值的元素 lrem queue:task 1 task1LREM参数说明参数值说明count 0从头开始删除count个匹配元素count 0从尾开始删除count 0删除所有匹配元素二、List应用场景2.1 消息队列经验之谈List做消息队列简单可靠但功能有限。复杂场景建议用专业的消息中间件。# 生产者左侧插入消息 lpush queue:order order_data_1 # 消费者右侧阻塞弹出消息 brpop queue:order 30 # 可靠消费弹出并备份 brpoplpush queue:order queue:processing 30消息队列模式对比模式命令组合特点简单队列LPUSH RPOP先进先出栈模式LPUSH LPOP后进先出可靠队列LPUSH BRPOPLPUSH失败可恢复多消费者LPUSH BRPOP多个消费者竞争2.2 最新列表# 添加最新文章左侧插入 lpush latest:articles article:1001 # 只保留最新10篇 ltrim latest:articles 0 9 # 获取最新文章列表 lrange latest:articles 0 92.3 时间线/动态# 发布动态 lpush timeline:user:1001 post:2001 # 获取用户时间线 lrange timeline:user:1001 0 20 # 分页获取 lrange timeline:user:1001 0 9 # 第1页 lrange timeline:user:1001 10 19 # 第2页2.4 分页查询# 假设每页10条 # 第1页索引0-9 lrange list:data 0 9 # 第2页索引10-19 lrange list:data 10 19 # 第N页索引(N-1)*10 到 N*10-1 lrange list:data 20 29三、Set命令详解3.1 Set的特点与底层实现实际场景Set的去重和集合运算能力让社交功能开发变得简单。Set是Redis的集合类型具有以下特点无序元素没有固定顺序不重复自动去重支持集合运算交集、并集、差集底层实现元素少且都是整数时使用intset否则使用hashtable3.2 基础操作命令# 添加元素 sadd tags:article:1 redis database nosql # 添加单个元素 sadd tags:article:1 cache # 获取所有元素 smembers tags:article:1 # 检查元素是否存在 sismember tags:article:1 redis # 移除元素 srem tags:article:1 nosql # 获取集合大小 scard tags:article:13.3 随机操作命令# 随机获取一个元素不移除 srandmember tags:article:1 # 随机获取多个元素 srandmember tags:article:1 3 # 随机弹出元素移除 spop tags:article:1 # 随机弹出多个元素 spop tags:article:1 23.4 集合运算命令# 准备测试数据 sadd set:a 1 2 3 4 5 sadd set:b 3 4 5 6 7 sadd set:c 5 6 7 8 9 # 交集同时属于多个集合的元素 sinter set:a set:b # 返回3 4 5 # 并集所有集合的元素合并 sunion set:a set:b # 返回1 2 3 4 5 6 7 # 差集第一个集合有但其他集合没有的元素 sdiff set:a set:b # 返回1 2 # 交集并存储 sinterstore set:a_b set:a set:b # 并集并存储 sunionstore set:a_b_union set:a set:b # 差集并存储 sdiffstore set:a_b_diff set:a set:b集合运算图解运算说明命令交集A ∩ BSINTER并集A ∪ BSUNION差集A - BSDIFF3.5 迭代命令# 迭代获取元素适合大集合 sscan tags:article:1 0 match re* count 10四、Set应用场景4.1 标签系统实际场景文章标签、用户标签、商品标签Set都能轻松搞定。# 文章添加标签 sadd article:1001:tags redis database nosql # 获取文章所有标签 smembers article:1001:tags # 标签下的文章 sadd tag:redis:articles 1001 1002 1003 # 获取标签下的所有文章 smembers tag:redis:articles # 检查文章是否有某标签 sismember article:1001:tags redis4.2 共同好友/共同关注# 用户关注列表 sadd user:1001:following 1002 1003 1004 1005 sadd user:1002:following 1003 1004 1006 1007 # 共同关注 sinter user:1001:following user:1002:following # 返回1003 1004 # 我关注的人中谁关注了他 sinter user:1001:following user:1002:followers # 可能认识的人他关注但我没关注的人 sdiff user:1002:following user:1001:following # 返回1006 10074.3 唯一性判断# 投票去重 sadd vote:article:1001 user:1001 sadd vote:article:1001 user:1002 sadd vote:article:1001 user:1001 # 自动去重 # 检查是否已投票 sismember vote:article:1001 user:1001 # 获取投票人数 scard vote:article:1001 # 签到统计 sadd sign:20240101 user:1001 user:1002 user:1003 sadd sign:20240102 user:1001 user:1002 user:1004 # 连续签到用户 sinter sign:20240101 sign:202401024.4 抽奖系统# 添加抽奖用户 sadd lottery:20240101 user:1001 user:1002 user:1003 user:1004 user:1005 # 随机抽取1个中奖用户不移除 srandmember lottery:20240101 # 随机抽取3个中奖用户 srandmember lottery:20240101 3 # 抽取并移除不可重复中奖 spop lottery:202401014.5 社交推荐# 用户A的好友 sadd friends:a 1002 1003 1004 # 用户B的好友 sadd friends:b 1003 1004 1005 # 共同好友 sinter friends:a friends:b # 推荐好友B的好友中A不认识的人 sdiff friends:b friends:a五、踩坑提醒List阻塞操作踩坑提醒阻塞操作使用不当会导致连接超时或资源浪费5.1 BLPOP/BRPOP注意事项问题1长时间阻塞# 阻塞时间设置为0表示永久等待 blpop queue:task 0 # 危险可能导致连接永久挂起 # 建议设置合理的超时时间 blpop queue:task 30 # 30秒超时问题2多列表阻塞顺序# 按顺序检查列表返回第一个非空列表的元素 blpop queue:high queue:low 30 # 如果queue:high有元素优先返回问题3客户端断开阻塞期间客户端断开Redis会自动取消阻塞应用层需要处理重连逻辑5.2 大列表操作问题LRANGE获取大量元素# 危险获取全部元素可能阻塞Redis lrange big:list 0 -1 # 建议分批获取 lrange big:list 0 99 lrange big:list 100 199问题LREM删除大量元素# 删除所有匹配元素时间复杂度O(n) lrem big:list 0 value # 建议使用LTRIM或重建列表5.3 大集合操作问题SMEMBERS获取大量元素# 危险返回所有元素可能阻塞Redis smembers big:set # 建议使用SSCAN迭代获取 sscan big:set 0 count 100问题集合运算结果过大# 大集合交集可能很慢 sinter big:set:a big:set:b # 建议先计算小集合的交集再判断六、List与Set对比6.1 功能对比对比项ListSet有序性有序无序重复性可重复不重复随机访问支持LINDEX不支持范围查询支持LRANGE不支持集合运算不支持支持阻塞操作支持不支持6.2 场景选择场景推荐理由消息队列List支持阻塞弹出最新列表List有序支持范围查询分页List支持索引访问去重Set自动去重标签Set无需顺序支持集合运算共同好友Set支持交集运算抽奖Set支持随机获取七、面试高频考点Q1List如何实现消息队列答案简单队列LPUSH RPOP先进先出可靠队列LPUSH BRPOPLPUSH失败可恢复多消费者LPUSH BRPOP竞争消费注意事项消息持久化需要开启AOF或RDB消息确认需要业务层实现复杂场景建议用专业消息队列RabbitMQ、KafkaQ2Set的集合运算时间复杂度是多少答案SINTERO(N*M)N是最小集合大小M是集合数量SUNIONO(N)N是所有集合元素总数SDIFFO(N)N是所有集合元素总数优化建议先计算小集合使用SINTERSTORE缓存结果Q3如何实现一个简单的抽奖系统答案# 添加参与用户 sadd lottery:20240101 user:1001 user:1002 user:1003 # 抽取中奖者不可重复中奖 spop lottery:20240101 # 抽取多个中奖者 spop lottery:20240101 3 # 抽取中奖者可重复中奖 srandmember lottery:20240101八、参考资料Redis Set命令文档Redis数据结构详解九、互动话题你在项目中用List做过消息队列吗遇到过什么问题或者用Set实现过有趣的社交功能欢迎在评论区分享你的实战经验下一篇我们将深入探讨ZSet和Bitmap的高级用法。