Redis 数据类型
Redis 是一个开源的高性能键值对数据库,支持多种数据类型,每种类型都有独特的应用场景。
一、五种基本数据类型
1. String(字符串)
String 是 Redis 最基本的数据类型,可以存储字符串、整数、浮点数或二进制数据(如图片)。
# 基本操作
SET key value # 设置值
GET key # 获取值
DEL key # 删除
SETNX key value # 不存在时设置(分布式锁基础)
SETEX key seconds value # 设置值并指定过期时间
# 数值操作
INCR key # 自增1
INCRBY key increment # 自增指定值
DECR key # 自减1
APPEND key value # 追加字符串应用场景:
- 缓存对象(JSON 序列化)
- 计数器(文章阅读量、点赞数)
- 分布式锁(SETNX)
- Session 共享
2. Hash(哈希)
Hash 是一个键值对集合,适合存储对象。
# 基本操作
HSET key field value # 设置字段
HGET key field # 获取字段
HMSET key field1 value1 field2 value2 # 批量设置
HMGET key field1 field2 # 批量获取
HGETALL key # 获取所有字段
HDEL key field # 删除字段
HEXISTS key field # 判断字段是否存在
HINCRBY key field increment # 字段自增
# 实战示例:存储用户信息
HSET user:1001 name "张三" age 25 email "zhangsan@example.com"
HGET user:1001 name # "张三"应用场景:
- 存储对象(用户信息、商品信息)
- 购物车(用户ID为key,商品ID为field,数量为value)
Hash vs String 存储对象:
| 对比项 | String (JSON) | Hash |
|---|---|---|
| 修改单个属性 | 需要读取全部、修改、写回 | 直接修改单个字段 |
| 内存占用 | 较高 | 较低 |
| 查询单个属性 | 需要解析JSON | 直接获取 |
| 适用场景 | 整体读写频繁 | 部分属性读写频繁 |
3. List(列表)
List 是一个双向链表,支持从两端插入和弹出。
# 基本操作
LPUSH key value # 左边插入
RPUSH key value # 右边插入
LPOP key # 左边弹出
RPOP key # 右边弹出
LRANGE key start stop # 获取范围元素
LLEN key # 获取长度
LINDEX key index # 获取指定位置元素
LREM key count value # 删除指定元素
# 阻塞操作
BLPOP key timeout # 阻塞式左边弹出
BRPOP key timeout # 阻塞式右边弹出
# 实战示例:消息队列
LPUSH queue:order "order:12345"
RPOP queue:order # 消费消息应用场景:
- 消息队列(LPUSH + BRPOP)
- 最新列表(最新文章、最新评论)
- 时间线(微博关注的人的动态)
4. Set(集合)
Set 是无序、不重复的字符串集合。
# 基本操作
SADD key member # 添加元素
SREM key member # 删除元素
SMEMBERS key # 获取所有元素
SISMEMBER key member # 判断元素是否存在
SCARD key # 获取元素个数
# 集合运算
SINTER key1 key2 # 交集
SUNION key1 key2 # 并集
SDIFF key1 key2 # 差集
# 实战示例:共同关注
SADD user:1001:follow "java" "redis" "mysql"
SADD user:1002:follow "java" "redis" "kafka"
SINTER user:1001:follow user:1002:follow # 共同关注:java, redis应用场景:
- 标签系统
- 共同关注/共同好友
- 抽奖系统(SRANDMEMBER 随机获取)
- 点赞/收藏(去重)
5. ZSet(有序集合)
ZSet 是有序、不重复的字符串集合,每个元素关联一个 score。
# 基本操作
ZADD key score member # 添加元素(带分数)
ZREM key member # 删除元素
ZSCORE key member # 获取元素分数
ZRANK key member # 获取元素排名(升序)
ZREVRANK key member # 获取元素排名(降序)
ZRANGE key start stop [WITHSCORES] # 范围查询(升序)
ZREVRANGE key start stop [WITHSCORES] # 范围查询(降序)
ZCARD key # 获取元素个数
# 分数操作
ZINCRBY key increment member # 增加分数
# 实战示例:排行榜
ZADD leaderboard 100 "player1"
ZADD leaderboard 200 "player2"
ZADD leaderboard 150 "player3"
ZREVRANGE leaderboard 0 9 WITHSCORES # Top 10 排行榜应用场景:
- 排行榜(游戏积分、热搜榜)
- 延时队列(score 为执行时间戳)
- 范围查询(分数段查询)
二、高级数据类型
1. Bitmap(位图)
Bitmap 不是独立的数据类型,而是基于 String 的位操作。
# 基本操作
SETBIT key offset value # 设置指定位
GETBIT key offset # 获取指定位
BITCOUNT key # 统计1的个数
BITOP operation destkey key [key...] # 位运算
# 实战示例:用户签到
SETBIT user:1001:sign:202601 0 1 # 1月1日签到
SETBIT user:1001:sign:202601 5 1 # 1月6日签到
BITCOUNT user:1001:sign:202601 # 统计签到天数
GETBIT user:1001:sign:202601 0 # 检查某天是否签到应用场景:
- 用户签到统计
- 在线状态统计
- 布隆过滤器基础
2. HyperLogLog
HyperLogLog 用于基数统计(不重复元素数量),占用空间极小(约 12KB)。
# 基本操作
PFADD key element [element...] # 添加元素
PFCOUNT key # 获取基数估计值
PFMERGE destkey sourcekey [sourcekey...] # 合并多个HyperLogLog
# 实战示例:网站UV统计
PFADD page:home:uv user1 user2 user3
PFADD page:home:uv user2 user4 # user2 不重复计数
PFCOUNT page:home:uv # 返回 4特点:
- 占用空间固定约 12KB
- 有约 0.81% 的误差率
- 适合大规模去重统计
3. Geo(地理位置)
Geo 用于存储地理位置信息,底层使用 ZSet。
# 基本操作
GEOADD key longitude latitude member # 添加地理位置
GEOPOS key member # 获取坐标
GEODIST key member1 member2 [unit] # 计算距离
GEORADIUS key longitude latitude radius unit # 查询半径内的元素
GEORADIUSBYMEMBER key member radius unit # 查询元素周围的位置
# 实战示例:附近的人/店铺
GEOADD locations 116.404 39.915 "天安门"
GEOADD locations 116.405 39.916 "故宫"
GEORADIUS locations 116.404 39.915 1 km # 查询1公里内的位置4. Stream
Stream 是 Redis 5.0 新增的数据类型,用于实现轻量级消息队列。
# 基本操作
XADD key * field value # 添加消息(* 表示自动生成ID)
XLEN key # 获取消息数量
XRANGE key - + # 获取所有消息
XREAD COUNT n STREAMS key $ # 读取消息($ 表示最新)
# 消费者组
XGROUP CREATE key groupname $ # 创建消费者组
XREADGROUP GROUP group consumer COUNT n STREAMS key > # 读取消息
# 实战示例:消息队列
XADD mystream * name "张三" age 25
XREAD COUNT 10 STREAMS mystream $三、数据类型选择指南
| 需求场景 | 推荐类型 | 说明 |
|---|---|---|
| 简单缓存 | String | 单个值存储 |
| 对象存储 | Hash | 部分属性频繁修改 |
| 列表/队列 | List | 有序可重复 |
| 去重集合 | Set | 无序不重复 |
| 排行榜 | ZSet | 需要排序 |
| 签到统计 | Bitmap | 位操作高效 |
| UV统计 | HyperLogLog | 大数据去重 |
| 位置服务 | Geo | 经纬度相关 |
| 消息队列 | Stream | 需要消费确认 |
四、面试高频问题
Q1: Redis 为什么快?
- 基于内存:数据存储在内存中,读写速度极快
- 单线程模型:避免线程切换开销,不存在并发竞争
- IO多路复用:使用 epoll 实现高并发连接
- 高效数据结构:SDS、压缩列表、跳表等优化
Q2: String 类型的最大大小?
512MB。由 Redis 配置 proto-max-bulk-len 决定。
Q3: Hash 类型适合存储什么?
适合存储对象,特别是需要频繁修改部分属性的场景。相比 JSON 存储,Hash 可以单独更新某个字段。
Q4: ZSet 底层实现?
- 同时使用压缩列表和跳表
- 元素数量少时用压缩列表
- 元素数量多时用跳表 + 字典
- 跳表保证有序性,字典保证 O(1) 查找
Q5: 如何实现分布式锁?
# 方式一:SETNX
SETNX lock:resource 1 # 获取锁
DEL lock:resource # 释放锁
# 方式二:SET 扩展命令(推荐)
SET lock:resource 1 NX PX 30000 # 获取锁,30秒过期
# 方式三:Redisson(生产推荐)
# 内置看门狗机制,自动续期五、最佳实践
1. Key 命名规范
业务名:对象名:id:属性
例如:user:1001:profile
order:12345:status2. 合理设置过期时间
- 缓存数据必须设置过期时间
- 热点数据可设置较长过期时间
- 避免大量 Key 同时过期
3. 选择合适的数据类型
- 能用 Hash 就不用多个 String
- 能用 Set/ZSet 就不要用 List 查找
- 注意大 Key 问题(单个 Key 的 Value 过大)
更新时间:2026年3月16日