【Redis】数据类型详解Day2(2026年)

写在前面

掌握Redis的数据类型是使用Redis的基础。不同的数据类型适用于不同的业务场景,选对类型能让你的系统性能翻倍。今天我们来全面了解Redis的5种基本数据类型。

文章目录


一、5种基本数据类型概述

实际场景:选择合适的数据类型,就像选择合适的工具,能让你的开发事半功倍。

Redis提供了5种基本数据类型,每种类型都有其独特的特点和适用场景。

数据类型 底层实现 特点 典型应用
String SDS(简单动态字符串) 最基础类型,可存字符串、整数、浮点数 缓存、计数器、分布式锁
Hash 哈希表+压缩列表 键值对集合,适合存储对象 用户信息、商品详情
List 双向链表+压缩列表 有序可重复,支持两端操作 消息队列、最新列表
Set 哈希表+整数集合 无序不重复,支持集合运算 标签、共同好友
ZSet 跳表+哈希表 有序不重复,带分数排序 排行榜、延时队列

二、String字符串类型

2.1 String的特点

经验之谈:String是最灵活的类型,但不要什么都往String里塞,该用Hash的时候别省。

String是Redis最基本的数据类型,可以存储:

  • 字符串
  • 整数
  • 浮点数
  • 二进制数据(如图片、序列化对象)

底层实现:使用SDS(Simple Dynamic String),相比C字符串有以下优势:

  • O(1)获取长度
  • 防止缓冲区溢出
  • 减少内存重分配次数
  • 二进制安全

2.2 基本命令示例

redis 复制代码
# 设置值
set user:1 "zhangsan"

# 获取值
get user:1

# 设置值并设置过期时间(秒)
setex session:abc 3600 "user_data"

# 仅当键不存在时设置
setnx lock:order 1

# 批量设置
mset key1 "value1" key2 "value2"

# 批量获取
mget key1 key2

# 数值操作
incr counter
incrby counter 10
decr counter

上述命令中,SETEX同时设置值和过期时间,适合缓存场景;SETNX实现分布式锁的基础;MSET/MGET批量操作提升效率。

2.3 适用场景

场景 实现方式 示例
缓存 SET/GET 缓存用户信息、商品详情
计数器 INCR/INCRBY 文章阅读量、点赞数
分布式锁 SETNX 防止重复下单
分布式ID INCR 生成唯一ID
Session共享 SETEX 集群环境会话管理

三、Hash哈希类型

3.1 Hash的特点

踩坑提醒:Hash适合存储对象,但如果字段很多且经常变动,要考虑内存占用。

Hash是一个键值对集合,特别适合存储对象。相比将对象JSON序列化后存为String:

对比项 Hash存储 String存储
内存占用 较小(ziplist编码时) 较大
部分更新 支持(HSET单字段) 需要整体更新
部分读取 支持(HGET单字段) 需要整体读取
适用场景 字段较多、需部分访问 字段少、整体读写

3.2 基本命令示例

redis 复制代码
# 设置单个字段
hset user:1 name "zhangsan"

# 设置多个字段
hmset user:1 name "zhangsan" age 25 city "beijing"

# 获取单个字段
hget user:1 name

# 获取多个字段
hmget user:1 name age

# 获取所有字段和值
hgetall user:1

# 获取所有字段名
hkeys user:1

# 获取所有值
hvals user:1

# 删除字段
hdel user:1 city

# 字段数值增减
hincrby user:1 age 1

# 检查字段是否存在
hexists user:1 name

3.3 适用场景

  1. 用户信息存储:用户ID为key,各属性为field
  2. 商品信息:商品ID为key,名称、价格、库存等为field
  3. 购物车:用户ID为key,商品ID为field,数量为value

四、List列表类型

4.1 List的特点

实际场景:List天生就是为队列设计的,LPUSH+RPOP就是简单的消息队列。

List是一个双向链表,支持从两端插入和弹出:

  • 有序:元素按插入顺序排列
  • 可重复:允许重复元素
  • 双向操作:支持左右两端操作

底层实现

  • 元素少时使用ziplist(压缩列表)
  • 元素多时使用quicklist(双向链表)

4.2 基本命令示例

redis 复制代码
# 左侧插入
lpush queue:task "task1"

# 右侧插入
rpush queue:task "task2"

# 左侧弹出
lpop queue:task

# 右侧弹出
rpop queue:task

# 获取列表长度
llen queue:task

# 获取指定范围元素
lrange queue:task 0 -1

# 阻塞弹出(用于消息队列)
blpop queue:task 30

# 通过索引获取元素
lindex queue:task 0

# 设置指定索引的值
lset queue:task 0 "new_task"

注意事项

  • LRANGE的索引从0开始,-1表示最后一个元素
  • BLPOP是阻塞操作,会一直等待直到有元素或超时

4.3 适用场景

场景 命令组合 说明
消息队列 LPUSH + BRPOP 异步任务处理
最新列表 LPUSH + LRANGE 最新文章、最新评论
时间线 LPUSH + LTRIM 保留最近N条记录

五、Set集合类型

5.1 Set的特点

经验之谈:Set的集合运算(交集、并集、差集)是它的杀手锏功能,用好了能省很多代码。

Set是无序、不重复的字符串集合:

  • 无序:元素没有固定顺序
  • 不重复:自动去重
  • 支持集合运算:交集、并集、差集

底层实现

  • 元素少且都是整数时使用intset
  • 否则使用hashtable

5.2 基本命令示例

redis 复制代码
# 添加元素
sadd tags:article:1 "redis" "database" "nosql"

# 获取所有元素
smembers tags:article:1

# 检查元素是否存在
sismember tags:article:1 "redis"

# 移除元素
srem tags:article:1 "nosql"

# 获取集合大小
scard tags:article:1

# 随机获取元素
srandmember tags:article:1

# 随机弹出元素
spop tags:article:1

# 交集
sinter tags:article:1 tags:article:2

# 并集
sunion tags:article:1 tags:article:2

# 差集
sdiff tags:article:1 tags:article:2

5.3 适用场景

场景 实现方式 示例
标签系统 SADD/SMEMBERS 文章标签、用户标签
共同好友 SINTER 社交推荐
唯一性判断 SADD返回值 投票去重、签到统计
抽奖系统 SPOP/SRANDMEMBER 随机抽取用户

六、ZSet有序集合类型

6.1 ZSet的特点

踩坑提醒:ZSet功能强大但内存占用较高,数据量大时要权衡使用。

ZSet是有序、不重复的字符串集合,每个元素关联一个分数(score):

  • 有序:按分数排序
  • 不重复:元素唯一
  • 可按分数范围查询

底层实现

  • 使用skiplist(跳表)+ hashtable
  • 跳表保证有序和范围查询效率
  • 哈希表保证O(1)查找

6.2 基本命令示例

redis 复制代码
# 添加元素
zadd leaderboard 100 "user1"
zadd leaderboard 200 "user2" 150 "user3"

# 获取元素分数
zscore leaderboard "user1"

# 获取排名(从0开始,升序)
zrank leaderboard "user1"

# 获取排名(降序)
zrevrank leaderboard "user1"

# 获取指定范围元素(按分数)
zrangebyscore leaderboard 100 200

# 获取指定排名范围元素
zrange leaderboard 0 9 withscores

# 获取降序排名范围
zrevrange leaderboard 0 9 withscores

# 增加分数
zincrby leaderboard 50 "user1"

# 移除元素
zrem leaderboard "user1"

# 获取集合大小
zcard leaderboard

# 统计分数范围内的元素数量
zcount leaderboard 100 200

6.3 适用场景

场景 实现方式 示例
排行榜 ZADD + ZREVRANGE 游戏积分榜、热搜榜
延时队列 分数为执行时间戳 定时任务调度
带权重的标签 分数为权重 标签推荐系统
范围查询 ZRANGEBYSCORE 按时间范围查询

七、数据类型选择对比表

需求场景 推荐类型 理由
简单缓存 String 简单直接,性能最优
对象存储 Hash 支持部分读写,内存效率高
队列/栈 List 天然支持两端操作
去重集合 Set 自动去重,支持集合运算
排序需求 ZSet 自动排序,支持范围查询
计数器 String INCR原子操作
时间线 List/ZSet List简单,ZSet支持按时间范围查询

八、踩坑提醒:大key问题

踩坑提醒:大key是Redis性能杀手,务必重视!

什么是大key

  • String类型:value超过10KB
  • 集合类型:元素数量超过5000个

大key的危害

  1. 内存不均衡:导致主从同步延迟
  2. 阻塞操作:删除大key会阻塞Redis
  3. 网络拥塞:传输大key占用带宽

如何发现大key

shell 复制代码
# 使用redis-cli扫描
redis-cli --bigkeys

# 使用memory命令
memory usage keyname

如何处理大key

  1. 拆分:将大key拆分为多个小key
  2. 本地缓存:大value考虑本地缓存
  3. 异步删除:使用UNLINK替代DEL

九、面试高频考点

Q1:Redis的五种数据类型底层实现是什么?

答案

  • String:SDS(简单动态字符串)
  • Hash:ziplist + hashtable
  • List:quicklist(ziplist + linkedlist)
  • Set:intset + hashtable
  • ZSet:ziplist + skiplist + hashtable

Q2:为什么Redis用跳表而不是红黑树实现ZSet?

答案

  1. 跳表实现更简单,易于调试和维护
  2. 跳表支持范围查询更高效
  3. 跳表内存占用与红黑树相当
  4. 跳表并发操作更容易实现

Q3:如何选择数据类型?

答案

根据业务需求选择:

  • 简单KV存储用String
  • 对象存储用Hash
  • 队列用List
  • 去重用Set
  • 排序用ZSet
  • 同时考虑内存占用和访问效率

十、参考资料

Redis数据类型官方文档


十一、互动话题

你在实际项目中用过哪些Redis数据类型?有没有遇到过选型错误导致的性能问题?欢迎在评论区分享你的经验!

下一篇我们将深入探讨String和Hash的详细命令与应用场景。

相关推荐
Trouvaille ~1 小时前
【Redis篇】List 列表:双端队列与消息队列的完美实现
数据库·redis·list·双端队列·后端开发·quicklist·zoplist
Cloud_Shy6181 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第一章 Item 4 - 6)
android·数据库·论文阅读·python
土狗TuGou1 小时前
SQL内功笔记 · 第7篇:CTE&临时表&递归
数据库·笔记·后端·sql·mysql
XiYang-DING1 小时前
【Spring】日志
java·数据库·spring
我是唐青枫2 小时前
MySQL EXISTS 详解:存在性判断、NOT EXISTS 与实战示例
数据库·mysql
Reisentyan2 小时前
[Pro]GoLang Learn Data Day 5
开发语言·后端·golang
努力发光的程序员2 小时前
面试官与程序员谢飞机的3轮Java大厂面试问答实录:涵盖Spring Boot、微服务与数据库技术
java·jvm·spring boot·redis·面试·hibernate·microservices
我叫张小白。2 小时前
Redis的缓存雪崩、击穿、穿透和解决方案
数据结构·redis·fastapi·缓存穿透·缓存击穿·雪崩·热点key问题