知识模块
☕ Java 知识模块
十、中间件
Redis 数据类型

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 为什么快?

  1. 基于内存:数据存储在内存中,读写速度极快
  2. 单线程模型:避免线程切换开销,不存在并发竞争
  3. IO多路复用:使用 epoll 实现高并发连接
  4. 高效数据结构: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:status

2. 合理设置过期时间

  • 缓存数据必须设置过期时间
  • 热点数据可设置较长过期时间
  • 避免大量 Key 同时过期

3. 选择合适的数据类型

  • 能用 Hash 就不用多个 String
  • 能用 Set/ZSet 就不要用 List 查找
  • 注意大 Key 问题(单个 Key 的 Value 过大)

更新时间:2026年3月16日