导读:本期聚焦于唐僧创作的《Redis五种基本数据类型有哪些?各自的应用场景和底层实现是什么?》,敬请观看详情。Redis作为最流行的内存数据库之一,其核心魅力在于丰富的数据结构设计。本文围绕String字符串、Hash哈希、List列表、Set集合和ZSet有序集合这五种基本类型展开,详细讲解每种类型的常用命令、底层数据结构演变、以及在不同业务场景下的选型思路。比如缓存对象该用String还是Hash,排行榜为什么优先选ZSet,消息队列能否用List实现等问题都会一一解答。读完这篇文章,你对Redis的数据建模能力会有一个系统性的认识,在面试和实际项目中都能更加从容地应对。

Redis之所以能在众多内存数据库中脱颖而出,靠的不只是快,更是它把常用数据结构直接做成了可以远程操作的存储类型。开发者不需要把数据从数据库读出来再在应用层组装,而是直接让Redis帮你完成排序、去重、计数这些操作。Redis的基本数据类型共五种:String、Hash、List、Set和ZSet,理解它们的特性和适用场景,是用好Redis的第一步。

Redis五种基本数据类型有哪些?各自的应用场景和底层实现是什么?

一、String字符串:最简单也最全能的类型

String是Redis中最基础的数据类型,但它能存的远不止字符串。一个String类型的key可以存储字符串、整数、浮点数,甚至是二进制数据(比如序列化后的对象、图片字节流),单个值最大支持512MB。这个上限在日常业务中几乎不会成为瓶颈,但需要注意如果真的往里塞大对象,网络传输和反序列化的开销会很明显。

String的常用命令比较直观:SET设置值、GET取值、INCRDECR做原子自增自减、SETNX实现不存在才写入的语义,这个语义正是分布式锁的第一种实现方式。原子性是关键:多个客户端同时执行INCR,Redis保证每次操作都是串行执行的,不会出现并发丢失更新,这一点比自己写代码加锁要省心得多。

SET user:1:name "zhangsan"
GET user:1:name
INCR article:1001:views        # 阅读量原子自增
SETNX lock:order:2001 1        # 不存在才能设置,可用来做简易分布式锁
SETEX session:abc 1800 "uid=42"  # 设置值同时指定30分钟过期

典型应用场景包括:常规缓存(缓存用户信息、配置项)、计数器(点赞数、浏览量、限流计数)、分布式锁、全局唯一ID生成(用INCR配合日期拼接)。存对象时通常把对象序列化成JSON字符串再存入,取出来反序列化,简单粗暴但有效。

二、Hash哈希:把对象拆成字段来存

Hash类型相当于一个String的集合,它把一个key下面的内容组织成field-value对的形式。用Hash存用户对象时,可以把name、age、city分别作为field存储。这样做最大的好处是可以单独读写某个字段,而不需要把整个对象序列化反序列化一遍。假设用户对象有几十个字段,你只想更新一个昵称,用String存JSON就得整个读出来改完再写回去,用Hash只需一条HSET user:1 name "lisi"就完成了。

常用命令包括:HSET设置字段、HGET获取字段、HGETALL获取所有字段、HINCRBY对字段值自增、HEXISTS判断字段是否存在。需要注意Hash中没有嵌套结构,field的值只能是字符串,不能在Hash里再套一个Hash,复杂对象还是得靠序列化。

HSET user:1 name "zhangsan" age 28 city "beijing"
HGET user:1 age
HGETALL user:1
HINCRBY user:1 login_count 1

底层实现上,Hash在小数据量时使用listpack(早期版本是ziplist)这种紧凑的连续内存结构,节省内存开销;当元素数量或单个值大小超过阈值时,会转换为Hashtable。这也是Redis在内存占用和查询性能之间做的经典权衡。应用场景主要是对象缓存、购物车(用户id为key,商品id为field,数量为value)等需要局部读写的场合。

三、List列表:有序可重复的双端队列

List是一个双向链表结构,元素有序且可以重复,支持从两端压入和弹出元素。这个特性让它天然适合做消息队列的简化版:生产者用LPUSH往队头塞数据,消费者用BRPOP阻塞式地从队尾取数据,形成先进先出的消费模型。BRPOP的阻塞特性意味着消费者在没有消息时不会空转轮询,可以挂起等待,省CPU。

常用命令有:LPUSHRPUSH分别从左、右两端插入元素,LPOPRPOP从两端弹出,LRANGE按索引范围查询,LINDEX取指定位置元素。两端操作的时间复杂度都是O(1),但中间位置的访问是O(N),所以不要把List当数组随机访问用。

LPUSH task:queue "send_email:1001"
LPUSH task:queue "send_sms:1002"
BRPOP task:queue 5       # 阻塞最多5秒等待消息
LRANGE task:queue 0 -1   # 查看队列中所有任务

底层实现上,List统一使用quicklist(快速列表),它是一种以listpack为节点的双向链表,兼顾了内存紧凑性和两端操作的高效性。应用场景包括简单消息队列、最新消息列表(朋友圈动态、微博时间线)、操作日志截断等。不过要提醒一句,用List做消息队列有硬伤:没有ACK机制,消息弹出后消费失败就丢了,且无法多消费者按主题广播,严肃的队列需求还是应该用专业的消息中间件。

四、Set集合:无序去重的利器

Set是一个无序、元素唯一的集合,底层在元素都是整数且数量不多时使用intset整数集合,否则使用Hashtable。它的核心价值在于去重和集合运算。往Set里塞一万个元素,重复插入不会产生任何效果,判断某个元素是否存在是O(1)的操作,这比在数据库里建唯一索引再查询要轻量得多。

更强大的是集合间的交并差运算:SINTER求交集、SUNION求并集、SDIFF求差集。比如共同好友功能,把每个用户的好友存成一个Set,两个人的共同好友就是一条SINTER命令的事。抽奖场景也很常见,用SPOP随机弹出元素实现随机抽取且不重复中奖。

SADD user:1:friends "u2" "u3" "u4"
SADD user:2:friends "u3" "u4" "u5"
SINTER user:1:friends user:2:friends    # 共同好友: u3 u4
SISMEMBER user:1:friends "u2"           # 判断是否是好友
SPOP lottery:pool                        # 随机弹出一名中奖者

典型场景包括:标签系统(用户打标签、按标签圈人)、共同好友、抽奖、签到去重、黑名单白名单校验。需要注意集合是无序的,不要依赖元素的插入顺序。

五、ZSet有序集合:排行榜的标配

ZSet在Set的基础上给每个元素关联了一个double类型的分数(score),并按分数有序排列。它是Redis五种基本类型中功能最丰富的一种,既能像Set一样去重,又能按分数范围高效查询。排行榜类的需求几乎就是为ZSet量身定做的:把用户id作为成员,分数作为积分,实时排名一条ZREVRANGE命令就能拿到。

常用命令:ZADD添加成员并指定分数、ZSCORE查分数、ZRANGE按分数升序取区间、ZREVRANGE降序取区间、ZRANKZREVRANK查成员排名、ZINCRBY给成员加分。如果需要排名并列显示,分数可以拼上时间戳或其它辅助字段做加权处理。

ZADD rank:game 100 "player:1" 250 "player:2" 180 "player:3"
ZINCRBY rank:game 50 "player:1"            # player:1 加50分
ZREVRANGE rank:game 0 2 WITHSCORES         # 前三名及分数
ZREVRANK rank:game "player:2"              # player:2 的排名
ZRANGEBYSCORE rank:game 150 200            # 分数在150到200之间的成员

底层实现方面,ZSet在小数据量时使用listpack,数据量增大后转为skiplist(跳表)加Hashtable的组合:跳表负责有序范围查询,Hashtable负责按成员快速定位分数。跳表是一种概率平衡的多层链表,实现比红黑树简单得多,范围查询性能也更友好,这是Redis作者选择跳表的重要原因。应用场景涵盖排行榜、延迟队列(score存时间戳,定时扫描到期任务)、滑动窗口限流、按权重排序的各类业务。

选型思路与常见误区

面对一个业务需求,怎么选类型?可以先问自己三个问题:数据需不需要去重?需不需要有序?需不需要按字段局部访问?不需要去重且是简单键值对就用String;是对象且经常改单个字段就用Hash;需要队列语义或按插入顺序访问就用List;只需要去重和集合运算就用Set;去重同时还要排序就用ZSet。

常见误区有两个。一是习惯性把所有东西都序列化成JSON塞进String,功能上没问题,但每次修改都要整存整取,在高频更新场景下浪费严重,这类数据换Hash往往更合适。二是把List当数组频繁访问中间元素,或把Set当有序结构使用,都是对类型特性理解不到位导致的性能问题。真正用好Redis的关键,在于把业务操作语义和Redis提供的数据结构能力对齐,让计算尽量靠近数据,这样才能发挥出它作为数据结构服务器的全部价值。

Redis数据类型StringHash修改时间:2026-09-12 22:18:45

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260912/55591.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。