第 2 章:五大基础数据类型
jerry北京市2026年4月24日Redis 5 次阅读 约 18 分钟

掌握 String、List、Hash、Set、Sorted Set 的核心命令、底层编码和典型使用场景。
2.1 String(字符串)
最基础的类型,可以存储字符串、整数或浮点数,最大 512MB。
常用命令
# 基本操作
SET key value # 设置值
GET key # 获取值
DEL key # 删除
STRLEN key # 获取长度
# 设置选项
SET key value EX 60 # 设置值并指定过期时间(秒)
SET key value PX 60000 # 设置值并指定过期时间(毫秒)
SET key value NX # 仅当 key 不存在时设置(分布式锁核心)
SET key value XX # 仅当 key 存在时设置
SETNX key value # 等价于 SET key value NX
SETEX key 60 value # 等价于 SET key value EX 60
# 批量操作
MSET k1 v1 k2 v2 k3 v3 # 批量设置
MGET k1 k2 k3 # 批量获取
# 数值操作
SET counter 100
INCR counter # +1 → 101
DECR counter # -1 → 100
INCRBY counter 10 # +10 → 110
DECRBY counter 5 # -5 → 105
INCRBYFLOAT counter 1.5 # +1.5 → 106.5
# 追加
APPEND key " world" # 追加字符串
# 获取子串
GETRANGE key 0 4 # 获取索引 0-4 的子串
# 先获取旧值再设置新值
GETSET key newvalue # 返回旧值(Redis 6.2+ 用 GETDEL/GETEX)
底层编码
| 数据 | 编码 | 说明 |
|---|---|---|
| 整数(≤ long 范围) | int | 直接存储整数值 |
| 短字符串(≤ 44 字节) | embstr | 一次内存分配,SDS 和 redisObject 连续 |
| 长字符串(> 44 字节) | raw | 两次内存分配,SDS 和 redisObject 分离 |
SET num 12345
OBJECT ENCODING num # "int"
SET short "hello"
OBJECT ENCODING short # "embstr"
SET long "aaaa...(超过44字节)"
OBJECT ENCODING long # "raw"
应用场景
- 缓存:
SET user:1001 "{json数据}" EX 3600 - 计数器:
INCR article:1001:views - 分布式锁:
SET lock:order NX EX 30 - 分布式 ID:
INCR global:id
2.2 List(列表)
有序的字符串列表,支持从两端插入和弹出,底层是双向链表(quicklist)。
常用命令
# 插入
LPUSH list a b c # 左侧插入:c b a
RPUSH list d e # 右侧插入:c b a d e
# 弹出
LPOP list # 弹出左侧第一个:c
RPOP list # 弹出右侧第一个:e
# 阻塞弹出(消息队列常用)
BLPOP list 10 # 阻塞等待 10 秒,有数据则弹出
BRPOP list 10
# 查看
LRANGE list 0 -1 # 获取所有元素
LRANGE list 0 2 # 获取前 3 个
LLEN list # 列表长度
LINDEX list 0 # 获取指定索引的元素
# 修改
LSET list 0 "new" # 设置索引 0 的值
LINSERT list BEFORE "b" "x" # 在 b 前面插入 x
# 删除
LREM list 2 "a" # 从左侧删除 2 个值为 a 的元素
LTRIM list 0 99 # 只保留索引 0-99 的元素
# 移动
RPOPLPUSH source dest # 从 source 右侧弹出,推入 dest 左侧
LMOVE source dest LEFT RIGHT # Redis 6.2+,更灵活的移动
应用场景
- 消息队列:
LPUSH + BRPOP(简单队列) - 最新消息列表:
LPUSH + LTRIM(保留最新 N 条) - 时间线:微博/朋友圈的 Feed 流
# 示例:最新 10 条消息
LPUSH news:latest "新闻1"
LPUSH news:latest "新闻2"
LTRIM news:latest 0 9 # 只保留最新 10 条
LRANGE news:latest 0 -1 # 获取所有
2.3 Hash(哈希)
键值对集合,适合存储对象,类似于 Java 的 HashMap。
常用命令
# 设置
HSET user:1001 name "Alice" age 30 city "Beijing"
HSETNX user:1001 email "alice@example.com" # 字段不存在时才设置
# 获取
HGET user:1001 name # "Alice"
HMGET user:1001 name age # "Alice" "30"
HGETALL user:1001 # 获取所有字段和值
HKEYS user:1001 # 获取所有字段名
HVALS user:1001 # 获取所有值
# 删除
HDEL user:1001 city
# 判断
HEXISTS user:1001 name # 1(存在)
HLEN user:1001 # 字段数量
# 数值操作
HINCRBY user:1001 age 1 # age + 1
HINCRBYFLOAT user:1001 score 1.5
底层编码
| 条件 | 编码 | 说明 |
|---|---|---|
| 字段数 ≤ 128 且所有值 ≤ 64 字节 | listpack(7.0+)/ ziplist | 紧凑存储,省内存 |
| 超过上述限制 | hashtable | 标准哈希表 |
应用场景
- 存储对象:
HSET user:1001 name "Alice" age 30 - 购物车:
HSET cart:user1001 item:2001 3(商品 ID → 数量) - 计数器组:
HINCRBY article:1001 likes 1
Hash vs String 存储对象的对比:
| 方式 | 优点 | 缺点 |
|---|---|---|
| String(JSON) | 序列化简单,一次读取 | 修改单个字段需要全量读写 |
| Hash | 可以单独读写字段,省带宽 | 不支持嵌套结构 |
2.4 Set(集合)
无序、不重复的字符串集合,支持交集、并集、差集运算。
常用命令
# 添加
SADD tags "go" "redis" "docker"
# 查看
SMEMBERS tags # 所有成员
SCARD tags # 成员数量
SISMEMBER tags "go" # 是否存在:1
SRANDMEMBER tags 2 # 随机返回 2 个成员
# 删除
SREM tags "docker" # 删除指定成员
SPOP tags # 随机弹出一个成员
# 集合运算
SADD set1 a b c d
SADD set2 c d e f
SINTER set1 set2 # 交集:c d
SUNION set1 set2 # 并集:a b c d e f
SDIFF set1 set2 # 差集(set1 有但 set2 没有):a b
# 将运算结果存储到新集合
SINTERSTORE result set1 set2
应用场景
- 标签系统:
SADD article:1001:tags "go" "redis" - 共同好友:
SINTER user:1001:friends user:1002:friends - 抽奖:
SRANDMEMBER lottery 3(随机抽 3 人) - 点赞:
SADD article:1001:likes user:2001 - 唯一计数:
SCARD article:1001:likes
2.5 Sorted Set(有序集合)
每个成员关联一个分数(score),按分数排序,成员唯一但分数可以重复。
常用命令
# 添加
ZADD leaderboard 100 "Alice" 95 "Bob" 88 "Charlie"
# 查看
ZRANGE leaderboard 0 -1 # 按分数升序
ZRANGE leaderboard 0 -1 WITHSCORES # 带分数
ZREVRANGE leaderboard 0 2 # 按分数降序,前 3 名
ZRANGEBYSCORE leaderboard 90 100 # 分数在 90-100 之间
ZSCORE leaderboard "Alice" # 获取分数:100
ZRANK leaderboard "Alice" # 排名(升序,从 0 开始)
ZREVRANK leaderboard "Alice" # 排名(降序)
ZCARD leaderboard # 成员数量
ZCOUNT leaderboard 90 100 # 分数在 90-100 的数量
# 修改
ZINCRBY leaderboard 5 "Bob" # Bob 加 5 分
# 删除
ZREM leaderboard "Charlie"
ZREMRANGEBYSCORE leaderboard 0 60 # 删除分数 0-60 的成员
ZREMRANGEBYRANK leaderboard 0 2 # 删除排名 0-2 的成员
# 集合运算
ZUNIONSTORE dest 2 zset1 zset2 WEIGHTS 1 2 # 并集,zset2 权重 x2
ZINTERSTORE dest 2 zset1 zset2 # 交集
底层编码
| 条件 | 编码 | 说明 |
|---|---|---|
| 成员数 ≤ 128 且所有值 ≤ 64 字节 | listpack / ziplist | 紧凑存储 |
| 超过上述限制 | skiplist + hashtable | 跳表 + 哈希表 |
应用场景
- 排行榜:
ZADD + ZREVRANGE - 延迟队列:score 存时间戳,定时取出到期任务
- 滑动窗口限流:score 存时间戳
# 示例:排行榜
ZADD game:leaderboard 1500 "player:1001"
ZADD game:leaderboard 2300 "player:1002"
ZADD game:leaderboard 1800 "player:1003"
# 获取 Top 10
ZREVRANGE game:leaderboard 0 9 WITHSCORES
# 获取某玩家排名
ZREVRANK game:leaderboard "player:1002" # 0(第一名)
2.6 数据类型选择指南
| 需求 | 推荐类型 | 说明 |
|---|---|---|
| 简单缓存 | String | JSON 序列化存储 |
| 对象属性 | Hash | 可单独读写字段 |
| 队列/栈 | List | LPUSH/RPOP 或 RPUSH/LPOP |
| 去重集合 | Set | 自动去重 |
| 排行榜 | Sorted Set | 按分数排序 |
| 计数器 | String(INCR) | 原子递增 |
| 二值状态 | Bitmap | 签到、在线状态 |
| 基数统计 | HyperLogLog | UV 统计 |
| 地理位置 | GEO | 附近的人 |
2.7 面试要点
-
Redis 有哪些数据类型?
- 5 种基础类型 + Bitmap、HyperLogLog、GEO、Stream
-
String 的三种编码?
- int(整数)、embstr(短字符串 ≤ 44 字节)、raw(长字符串)
-
Hash 和 String 存对象的区别?
- Hash 可以单独读写字段,String 需要全量序列化/反序列化
-
Sorted Set 的底层实现?
- 小数据量用 listpack/ziplist,大数据量用 skiplist + hashtable
-
List 实现消息队列的局限?
- 不支持消费确认、不支持消费组、消息丢失风险
练习
- 使用 String 实现一个简单的访问计数器
- 使用 Hash 存储用户信息,实现增删改查
- 使用 Set 实现两个用户的共同好友查询
- 使用 Sorted Set 实现一个实时排行榜
评论
登录 后发表评论
暂无评论