Redis有哪五种基本数据类型?

来源:SpringBoot教程作者:乐少头衔:工程师
导读:本期聚焦于乐少创作的《Redis有哪五种基本数据类型?》,敬请观看详情。想用好Redis,首先得弄清楚它提供的五种基本数据类型——字符串、列表、集合、有序集合和哈希。这五种类型覆盖了绝大多数缓存和计数场景,每种类型都有独特的内部编码和适用边界。字符串是最基础的类型,可以存数字并原子递增;列表适合做消息队列或最新列表;集合用于去重、标签系统;有序集合支持按分数排序,常用于排行榜;哈希适合存储对象属性。理解它们的底层实现(如SDS、quicklist、skiplist)有助于避免用错类型导致性能问题。本文将逐一拆解这些类型的命令、编码方式和典型应用。

Redis作为高性能的内存键值数据库,其核心价值不仅在于极快的读写速度,更在于它提供了丰富的数据类型抽象。所谓数据类型,本质上是Redis对存储值结构的逻辑划分,使用者不必关心底层如何存储,只需根据业务语义选择合适类型,就能获得相应的操作命令和性能保证。Redis目前支持字符串、列表、集合、有序集合、哈希、Stream、Bitmap、HyperLogLog等多种数据结构,其中字符串、列表、集合、有序集合和哈希被称为五种基本数据类型,它们是Redis使用频率最高、覆盖场景最广的部分。本文逐一拆解这五种类型的命令、底层编码以及典型应用场景,帮助读者建立清晰的选择依据。

Redis有哪五种基本数据类型?

在实际项目中,选错数据类型往往会导致性能下降或代码复杂化。例如用字符串存储一个对象,每次修改一个字段都要序列化整个对象;用列表实现去重功能,需要自行编写额外逻辑。理解每种类型的内部编码机制(如SDS、quicklist、skiplist、ziplist)以及适用边界,是Redis进阶的必经之路。下面从最简单的字符串类型开始介绍。

字符串(String)

字符串是Redis最基础的数据类型,所有键的值都可以看作字符串,但字符串类型的值并不仅限于文本内容。它是二进制安全的,可以存储任意二进制数据,比如图片、序列化后的对象或简单的数字。单个字符串值最大允许512MB,完全满足大多数缓存需求。常见的命令包括SETGETAPPENDSTRLEN等,其中SET还支持NX(仅当键不存在时设置)、EX(设置过期时间)等选项,这些选项让字符串类型在分布式锁、缓存穿透防护等场景下非常实用。

字符串类型的底层编码并不固定,Redis会根据值的内容和长度动态选择最合适的存储结构。当值为整数且长度不超过20位时,使用int编码,直接以C语言long类型存储;当值为短字符串(通常小于等于44字节)时,采用embstr编码,这种编码将RedisObject和SDS(简单动态字符串)分配在连续内存中,只需一次内存分配,减少碎片;当字符串较长时,则使用raw编码,RedisObject和SDS分开存储。通过OBJECT ENCODING key命令可以查看某个键当前使用的编码类型。

使用字符串时最常用的场景是缓存对象序列化后的JSON数据、计数器(利用INCRDECR命令原子递增递减)以及分布式锁(利用SET key value NX PX 30000实现带过期时间的锁)。需要注意的是,如果字符串中存储的是数字,不要使用APPEND命令拼接,应该使用INCRBY进行数值运算,避免因字符串拼接导致类型错误。下面是一个简单的计数器示例:

# 设置初始计数值
SET page_view 100
# 原子递增
INCR page_view
# 获取当前值
GET page_view
# 查看内部编码
OBJECT ENCODING page_view

此外,字符串类型还可以通过MSETMGET批量设置和获取多个键值对,有效减少网络往返次数,提高吞吐量。但批量操作的数据量不宜过大,否则会阻塞Redis单线程,影响其他命令执行。

列表(List)

列表类型用于存储一个有序的字符串序列,允许元素重复,并且可以从两端推入或弹出元素。它的底层实现是一个双向链表,但在Redis 3.2版本之后统一使用quicklist编码,该结构结合了linkedlist和ziplist的优点:quicklist由多个ziplist节点组成,每个ziplist内部存储若干元素,ziplist之间用指针连接成双向链表。这种设计既减少了链表节点的内存开销,又避免了ziplist在元素过多时的查询退化问题。

常用的列表命令包括LPUSH(左侧推入)、RPUSH(右侧推入)、LPOP(左侧弹出)、RPOP(右侧弹出)、LRANGE(获取指定范围元素)、LTRIM(修剪列表只保留指定范围)等。因为列表的两端操作复杂度都是O(1),所以非常适合作为轻量级消息队列使用:生产者使用RPUSH将消息放入队列尾部,消费者使用LPOP从头部取出消息。为了提升消费效率,Redis还提供了阻塞式弹出命令BLPOPBRPOP,当列表为空时命令会阻塞直到有元素到达或超时,这样消费者端就无需轮询空队列,节省CPU资源。

列表的另一个典型场景是保存最新N条记录,例如网站的最新评论、最新登录日志等。通过LPUSH插入新记录,然后执行LTRIM list 0 99只保留最新100条,即可实现一个简单的“最新动态”列表。以下代码演示了使用列表实现简单消息队列和最新记录维护:

# 生产者向队列尾部添加消息
RPUSH task_queue "任务1"
RPUSH task_queue "任务2"
# 消费者阻塞式获取消息(超时5秒)
BLPOP task_queue 5
# 保存最新3条登录日志
LPUSH login_log "用户A"
LPUSH login_log "用户B"
LPUSH login_log "用户C"
LTRIM login_log 0 2
LRANGE login_log 0 -1

需要注意,列表底层使用quicklist后,访问中间元素的时间复杂度并不是O(1),而是取决于ziplist节点数量,最坏可能退化为O(n)。因此列表不适合频繁通过索引访问元素,应优先使用两端操作。如果业务需要随机访问,应该考虑使用有序集合或Redis 5.0之后的Stream类型。

集合(Set)

集合类型用于存储多个互不相同的字符串元素,无序且自动去重。集合的底层编码有两种:当集合中所有元素都是整数且元素数量不超过512个时,使用intset(整数集合),它是一种紧凑的整数数组结构,支持二分查找;否则使用hashtable,即哈希表。intset在内存占用上远低于hashtable,而且Redis会自动在条件变化时进行编码转换,无需人工干预。

集合的常用命令包括SADD(添加元素)、SREM(删除元素)、SMEMBERS(获取所有成员)、SISMEMBER(判断成员是否存在)、SCARD(获取集合基数)等。集合最强大的能力在于集合运算:SINTER求交集、SUNION求并集、SDIFF求差集。这些运算可以轻松实现共同好友、用户标签交集、内容去重等功能。例如一个用户有多个标签,存储为集合后,可以通过交集找出同时拥有两个标签的用户群。

集合非常适合做抽奖系统或随机数的去重容器,因为SPOP命令可以随机弹出一个元素,SRANDMEMBER可以随机返回指定数量的不重复元素(或允许重复)。在一次抽奖活动中,把所有参与者放入集合,然后反复使用SPOP即可保证每个参与者最多中奖一次。演示如下:

# 添加参与者
SADD lottery "张三" "李四" "王五" "赵六"
# 随机抽出一名中奖者(该成员会从集合中移除)
SPOP lottery
# 随机返回2个不重复元素但不移除(适合展示候选名单)
SRANDMEMBER lottery 2
# 计算两个集合的交集(如用户A和用户B的共同标签)
SINTER user1_tags user2_tags

集合虽然好用,但也要注意当元素数量较多时,SMEMBERS返回所有元素可能会阻塞Redis,因为Redis是单线程的,大数据量返回会占用较长时间。此时应使用SSCAN命令分批迭代,或者考虑使用有序集合通过范围查询代替全量获取。

有序集合(Sorted Set)

有序集合(简称ZSet)是集合的升级版本,每个元素都关联一个double类型的分数(score),元素按score从小到大排序,score可以相同,此时按字典序排序,但元素本身不可重复。有序集合的底层编码在元素数量较少且所有元素长度较短时使用ziplist(压缩列表),否则使用skiplist(跳跃表)加dict(字典)的组合。skiplist负责按分值排序和范围查找,dict则负责O(1)时间获取元素的score,两者配合实现了高效的范围操作和成员定位。

有序集合的核心命令包括ZADD(添加或更新成员及score)、ZRANGE(按索引范围返回正序元素)、ZREVRANGE(逆序返回)、ZSCORE(获取成员分数)、ZRANK(获取成员排名,从0开始)、ZRANGEBYSCORE(按分数范围返回元素)等。排行榜是它最经典的应用场景:将用户ID作为成员,得分作为score,使用ZADD更新分数,ZREVRANGE获取排名靠前的用户,ZRANK查询某个用户的排名。由于score是double类型,还可以存储时间戳实现延迟队列,用score表示任务执行时间,消费者不断通过ZRANGEBYSCORE获取当前时间之前且尚未处理的任务。

有序集合在实现加权随机、时间线排序等功能时也非常有用。比如新闻推荐系统可以为每篇新闻计算一个热度分值,使用有序集合存储,每次展示时通过ZREVRANGE获取热度最高的几条。下面是一个排行榜的示例:

# 初始化排行榜
ZADD rank 100 "玩家A"
ZADD rank 85 "玩家B"
ZADD rank 92 "玩家C"
# 玩家A得分增加10
ZINCRBY rank 10 "玩家A"
# 获取排行榜前3名
ZREVRANGE rank 0 2 WITHSCORES
# 查询玩家B的排名(从0开始)
ZREVRANK rank "玩家B"

需要注意的是,有序集合在数据量较大时,因为需要维护skiplist和dict两份结构,内存开销会比普通集合高,这是用空间换时间。另外,ZRANGE按索引范围查找时,如果索引值很大(比如获取第100万到100万+10条),性能不理想,因为skiplist按索引定位只能逐步跨越,复杂度为O(log n)+m,但m较大时仍较慢。此时可考虑使用ZRANGEBYSCORE结合分数范围进行查询。

哈希(Hash)

哈希类型用于存储键值对集合,适合表示一个对象的多个属性。一个Redis哈希可以包含多个field-value对,每个field都是字符串,value也是字符串或数字。哈希的底层编码同样根据field数量和小大使用ziplist(当哈希元素个数不超过512且每个field和value长度均不超过64字节)或hashtable。使用ziplist时哈希的内存占用非常紧凑,当任一条件不满足时自动转换为hashtable。

哈希的命令非常直观:HSET设置单个字段,HMSET批量设置,HGET获取单个字段,HMGET批量获取,HGETALL获取所有字段和值,HINCRBY对字段值进行整数递增。相比使用字符串存储整个对象序列化后的JSON,哈希类型允许按字段独立读写,修改某一属性时无需重新序列化整个对象,也无需担心并发写入时的版本冲突。例如用户信息可以存储在哈希中:user:1001 的field为name、age、email等。使用哈希可以减少网络传输,提升局部更新效率。

哈希还非常适合实现购物车场景:以用户ID为键,商品ID为field,数量为value,使用HINCRBY修改数量,HDEL删除商品,HGETALL获取整个购物车。但需要注意的是,当哈希中的field非常多时,HGETALL会返回全部字段,可能会阻塞Redis,此时应该使用HSCAN分批遍历。另外,哈希与字符串的选择取决于业务需求:如果更新频繁且字段独立,选哈希;如果很少更新且读取完整对象,字符串更简单高效。一个购物车操作的演示如下:

# 添加商品到购物车
HSET cart:1001 "商品A" 2
HSET cart:1001 "商品B" 1
# 商品A数量增加1
HINCRBY cart:1001 "商品A" 1
# 删除商品B
HDEL cart:1001 "商品B"
# 获取购物车全部内容
HGETALL cart:1001

理解这五种基本数据类型的命令和底层编码后,开发者就能在大多数缓存和状态管理场景中做出合理选择。实际项目中还需要结合键的命名规范、过期时间设置以及Redis的内存淘汰策略,才能充分发挥Redis的性能优势。

Redis数据类型缓存修改时间:2026-09-19 01:03:43

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