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

文章目录
-
- 写在前面
- 一、5种基本数据类型概述
- 二、String字符串类型
-
- [2.1 String的特点](#2.1 String的特点)
- [2.2 基本命令示例](#2.2 基本命令示例)
- [2.3 适用场景](#2.3 适用场景)
- 三、Hash哈希类型
-
- [3.1 Hash的特点](#3.1 Hash的特点)
- [3.2 基本命令示例](#3.2 基本命令示例)
- [3.3 适用场景](#3.3 适用场景)
- 四、List列表类型
-
- [4.1 List的特点](#4.1 List的特点)
- [4.2 基本命令示例](#4.2 基本命令示例)
- [4.3 适用场景](#4.3 适用场景)
- 五、Set集合类型
-
- [5.1 Set的特点](#5.1 Set的特点)
- [5.2 基本命令示例](#5.2 基本命令示例)
- [5.3 适用场景](#5.3 适用场景)
- 六、ZSet有序集合类型
-
- [6.1 ZSet的特点](#6.1 ZSet的特点)
- [6.2 基本命令示例](#6.2 基本命令示例)
- [6.3 适用场景](#6.3 适用场景)
- 七、数据类型选择对比表
- 八、踩坑提醒:大key问题
- 九、面试高频考点
- 十、参考资料
- 十一、互动话题
一、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 适用场景
- 用户信息存储:用户ID为key,各属性为field
- 商品信息:商品ID为key,名称、价格、库存等为field
- 购物车:用户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的危害
- 内存不均衡:导致主从同步延迟
- 阻塞操作:删除大key会阻塞Redis
- 网络拥塞:传输大key占用带宽
如何发现大key
shell
# 使用redis-cli扫描
redis-cli --bigkeys
# 使用memory命令
memory usage keyname
如何处理大key
- 拆分:将大key拆分为多个小key
- 本地缓存:大value考虑本地缓存
- 异步删除:使用UNLINK替代DEL
九、面试高频考点
Q1:Redis的五种数据类型底层实现是什么?
答案:
- String:SDS(简单动态字符串)
- Hash:ziplist + hashtable
- List:quicklist(ziplist + linkedlist)
- Set:intset + hashtable
- ZSet:ziplist + skiplist + hashtable
Q2:为什么Redis用跳表而不是红黑树实现ZSet?
答案:
- 跳表实现更简单,易于调试和维护
- 跳表支持范围查询更高效
- 跳表内存占用与红黑树相当
- 跳表并发操作更容易实现
Q3:如何选择数据类型?
答案 :
根据业务需求选择:
- 简单KV存储用String
- 对象存储用Hash
- 队列用List
- 去重用Set
- 排序用ZSet
- 同时考虑内存占用和访问效率
十、参考资料
十一、互动话题
你在实际项目中用过哪些Redis数据类型?有没有遇到过选型错误导致的性能问题?欢迎在评论区分享你的经验!
下一篇我们将深入探讨String和Hash的详细命令与应用场景。