Redis 数据结构和使用详解(带示例)

发布于:2025-03-04 ⋅ 阅读:(15) ⋅ 点赞:(0)

Redis 支持的主要数据结构及其对应操作命令的详细解释,结合具体使用场景和示例:


1. 字符串(String)

  • 用途:存储文本、数值或二进制数据,适用于缓存、计数器等。

  • 常用命令

    • SET key value:设置键值对。
    • GET key:获取键对应的值。
    • INCR key:将键的值递增1(原子操作)。
    • EXPIRE key seconds:设置键的过期时间。
  • 示例

    SET user:1001:name "Alice"  # 存储用户名
    GET user:1001:name           # 返回 "Alice"
    INCR article:123:views       # 文章阅读量+1
    
  • 场景 1:缓存用户 Token

    # 存储 Token,有效期 1 小时
    SET user:1001:token "abc123" EX 3600
    # 返回:OK
    
    # 获取 Token
    GET user:1001:token
    # 返回:"abc123"
    
    # 检查剩余过期时间
    TTL user:1001:token
    # 返回:3590(剩余秒数)
    
  • 场景 2:计数器(文章阅读量)

    # 初始化阅读量
    SET article:2001:views 0
    # 返回:OK
    
    # 阅读量 +1
    INCR article:2001:views
    # 返回:1(递增后的值)
    
    # 批量递增(+5)
    INCRBY article:2001:views 5
    # 返回:6
    
  • 场景 3:分布式锁

    # 尝试获取锁(有效期 10 秒)
    SET order:lock "process123" NX PX 10000
    # 返回:OK(获取成功)或 nil(失败)
    
    # 释放锁(需值匹配)
    EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 order:lock process123
    # 返回:1(删除成功)或 0(失败)
    

2. 哈希(Hash)

  • 用途:存储对象字段,适合保存用户信息、商品属性等结构化数据。

  • 常用命令

    • HSET key field value:设置哈希字段值。
    • HGET key field:获取哈希字段值。
    • HGETALL key:获取所有字段和值。
  • 示例

    HSET user:1001 age 30 email "alice@example.com"  # 存储用户信息
    HGET user:1001 age                               # 返回 "30"
    HGETALL user:1001                                # 返回所有字段和值
    
  • 场景 1:存储用户信息

    # 添加用户字段
    HSET user:1001 name "Alice" age 30 email "alice@example.com"
    # 返回:3(添加的字段数)
    
    # 获取单个字段
    HGET user:1001 name
    # 返回:"Alice"
    
    # 获取所有字段
    HGETALL user:1001
    # 返回:
    # 1) "name"
    # 2) "Alice"
    # 3) "age"
    # 4) "30"
    # 5) "email"
    # 6) "alice@example.com"
    
  • 场景 2:商品库存管理

    # 设置商品库存
    HSET product:5001 stock 100 price 2999
    # 返回:2
    
    # 扣减库存(原子操作)
    HINCRBY product:5001 stock -1
    # 返回:99
    
    # 获取价格
    HGET product:5001 price
    # 返回:"2999"
    
  • 场景 3:配置中心

    # 存储服务配置
    HSET service:config timeout 5000 retry 3 enable_cache true
    # 返回:3
    
    # 修改配置
    HSET service:config timeout 10000
    # 返回:0(字段已存在,仅更新)
    
    # 删除配置字段
    HDEL service:config retry
    # 返回:1
    

3. 列表(List)

  • 用途:实现消息队列、最新消息列表(如微博时间线)。

  • 常用命令

    • LPUSH key value:从列表左侧插入元素。
    • RPOP key:从列表右侧弹出元素。
    • LRANGE key start end:获取列表范围内的元素。
  • 示例

    LPUSH news:latest "Article 1"  # 插入最新新闻
    LPUSH news:latest "Article 2"
    LRANGE news:latest 0 4         # 获取前5条新闻
    
  • 场景 1:消息队列

    # 生产者推送任务
    LPUSH task:queue "send_email:user1" "generate_report:user2"
    # 返回:2(队列长度)
    
    # 消费者获取任务
    RPOP task:queue
    # 返回:"send_email:user1"
    
    # 查看队列剩余任务
    LRANGE task:queue 0 -1
    # 返回:1) "generate_report:user2"
    
  • 场景 2:最新消息列表

    # 插入最新新闻
    LPUSH news:latest "Article 3" "Article 2" "Article 1"
    # 返回:3
    
    # 获取前 2 条新闻
    LRANGE news:latest 0 1
    # 返回:
    # 1) "Article 1"
    # 2) "Article 2"
    
  • 场景 3:阻塞队列

    # 消费者阻塞等待任务(超时 10 秒)
    BRPOP task:queue 10
    # 返回(如果有任务):
    # 1) "task:queue"
    # 2) "generate_report:user2"
    

4. 集合(Set)

  • 用途:存储唯一元素,支持交集、并集操作(如共同好友、标签系统)。

  • 常用命令

    • SADD key member:添加元素到集合。
    • SMEMBERS key:获取集合所有元素。
    • SINTER key1 key2:计算多个集合的交集。
  • 示例

    SADD user:1001:follows 2001 2002  # 用户1001关注2001和2002
    SADD user:1002:follows 2001 2003
    SINTER user:1001:follows user:1002:follows  # 返回共同关注用户2001
    
  • 场景 1:标签系统

    # 添加文章标签
    SADD article:3001:tags "tech" "redis" "database"
    # 返回:3
    
    # 查找共同标签
    SINTER article:3001:tags article:3002:tags
    # 返回(假设 article:3002 有 "tech" 和 "cloud"):
    # 1) "tech"
    
  • 场景 2:抽奖活动

    # 添加参与者
    SADD lottery:2023 "user100" "user200" "user300"
    # 返回:3
    
    # 随机抽取 1 名中奖者
    SRANDMEMBER lottery:2023
    # 返回:"user200"(随机结果)
    
    # 移除并返回中奖者
    SPOP lottery:2023
    # 返回:"user100"
    
  • 场景 3:黑白名单

    # 添加黑名单用户
    SADD blacklist:ip "192.168.1.1" "192.168.1.2"
    # 返回:2
    
    # 检查 IP 是否在黑名单
    SISMEMBER blacklist:ip "192.168.1.1"
    # 返回:1(存在)
    

5. 有序集合(Sorted Set)

  • 用途:排行榜、优先级队列(按分数排序)。

  • 常用命令

    • ZADD key score member:添加带分数的成员。
    • ZRANGE key start end [WITHSCORES]:按分数升序返回成员。
    • ZREVRANGE key start end:按分数降序返回成员。
  • 示例

    ZADD game:leaderboard 1500 "PlayerA"  # 添加玩家分数
    ZADD game:leaderboard 2000 "PlayerB"
    ZREVRANGE game:leaderboard 0 9 WITHSCORES  # 返回前10名玩家
    
  • 场景 1:游戏排行榜

    # 添加玩家分数
    ZADD game:leaderboard 1500 "PlayerA" 2000 "PlayerB" 1800 "PlayerC"
    # 返回:3
    
    # 获取前 3 名(降序)
    ZREVRANGE game:leaderboard 0 2 WITHSCORES
    # 返回:
    # 1) "PlayerB"
    # 2) "2000"
    # 3) "PlayerC"
    # 4) "1800"
    # 5) "PlayerA"
    # 6) "1500"
    
  • 场景 2:延时任务

    # 添加任务(时间戳为分数)
    ZADD tasks:delayed 1672531200 "task1" 1672617600 "task2"
    # 返回:2
    
    # 获取当前需处理的任务(分数 <= 当前时间戳)
    ZRANGEBYSCORE tasks:delayed -inf 1672531200
    # 返回:1) "task1"
    
  • 场景 3:热搜榜单

    # 更新关键词热度
    ZINCRBY hot:keywords 1 "redis"
    # 返回:"1"(当前分数)
    
    ZINCRBY hot:keywords 1 "java"
    # 返回:"1"
    
    # 获取 Top 10 热搜词
    ZREVRANGE hot:keywords 0 9 WITHSCORES
    # 返回:
    # 1) "redis"
    # 2) "1"
    # 3) "java"
    # 4) "1"
    

6. 地理位置(GEO)

  • 用途:存储和查询地理位置(附近的人、商家)。

  • 常用命令

    • GEOADD key longitude latitude member:添加地理坐标。
    • GEODIST key member1 member2 [unit]:计算两地距离。
    • GEORADIUS key longitude latitude radius unit:查找范围内的成员。
  • 示例

    GEOADD restaurants 116.404269 39.913818 "RestaurantA"  # 添加餐厅坐标
    GEORADIUS restaurants 116.405 39.914 2 km WITHDIST      # 查找2公里内的餐厅
    
  • 场景 1:附近餐厅查询

    # 添加餐厅坐标
    GEOADD restaurants 116.404269 39.913818 "RestaurantA" 116.407531 39.915264 "RestaurantB"
    # 返回:2
    
    # 查找 1 公里内的餐厅
    GEORADIUS restaurants 116.405285 39.912987 1 km WITHDIST
    # 返回:
    # 1) 1) "RestaurantA"
    #    2) "0.8923"
    
  • 场景 2:计算距离

    # 计算两餐厅距离
    GEODIST restaurants "RestaurantA" "RestaurantB" km
    # 返回:"0.312"(公里)
    
  • 场景 3:获取坐标

    # 获取餐厅坐标
    GEOPOS restaurants "RestaurantA"
    # 返回:
    # 1) 1) "116.404269"
    #    2) "39.913818"
    

7. 位图(Bitmap)

  • 用途:位操作(如用户签到、活跃统计)。

  • 常用命令

    • SETBIT key offset value:设置位的值(0或1)。
    • GETBIT key offset:获取位的值。
    • BITCOUNT key:统计值为1的位数。
  • 示例

    SETBIT user:1001:sign:202310 5 1  # 用户1001在10月6日签到
    BITCOUNT user:1001:sign:202310    # 统计本月签到天数
    
  • 场景 1:用户签到

    # 用户 1001 在 10 月 1 日签到(偏移量 0)
    SETBIT user:1001:sign:202310 0 1
    # 返回:0(之前位的值)
    
    # 检查 10 月 1 日是否签到
    GETBIT user:1001:sign:202310 0
    # 返回:1
    
  • 场景 2:活跃用户统计

    # 统计 10 月累计签到天数
    BITCOUNT user:1001:sign:202310
    # 返回:3(假设签到 3 天)
    
  • 场景 3:权限控制

    # 设置权限位(位 0: 读,位 1: 写)
    SETBIT user:1001:permissions 0 1
    SETBIT user:1001:permissions 1 0
    # 检查写权限
    GETBIT user:1001:permissions 1
    # 返回:0(无权限)
    

8. HyperLogLog

  • 用途:近似去重计数(如统计UV)。

  • 常用命令

    • PFADD key element:添加元素。
    • PFCOUNT key:统计唯一元素数量。
  • 示例

    PFADD daily_uv:20231001 "user1" "user2"  # 记录当日访问用户
    PFCOUNT daily_uv:20231001                # 返回近似UV数
    
  • 场景 1:UV 统计

    # 记录用户访问
    PFADD daily_uv:20231001 "user1" "user2" "user1"
    # 返回:1(新增唯一用户数)
    
    # 获取当日 UV
    PFCOUNT daily_uv:20231001
    # 返回:2
    
  • 场景 2:合并多日 UV

    # 合并 10 月 1 日和 2 日的 UV
    PFMERGE weekly_uv:20231001-07 daily_uv:20231001 daily_uv:20231002
    # 返回:OK
    
    # 获取周 UV
    PFCOUNT weekly_uv:20231001-07
    # 返回:5(假设两日共有 5 个唯一用户)
    

9. 流(Stream)

  • 用途:消息队列(支持消费者组、消息持久化)。

  • 常用命令

    • XADD key * field1 value1:添加消息。
    • XREAD COUNT num STREAMS key $:读取消息。
    • XGROUP CREATE key groupname $:创建消费者组。
  • 示例

    XADD order:stream * user "Alice" product "Phone"  # 发布订单消息
    XREAD COUNT 10 STREAMS order:stream 0             # 读取消息
    
  • 场景 1:订单消息队列

    # 发布订单消息
    XADD orders:* user_id 1001 product_id 2001 status "created"
    # 返回:"1672531200000-0"(消息 ID)
    
    # 读取最新消息
    XREAD COUNT 1 STREAMS orders:*
    # 返回:
    # 1) 1) "orders:*"
    #    2) 1) 1) "1672531200000-0"
    #          2) 1) "user_id"
    #             2) "1001"
    #             3) "product_id"
    #             4) "2001"
    #             5) "status"
    #             6) "created"
    
  • 场景 2:消费者组

    # 创建消费者组
    XGROUP CREATE orders:stream order_group $
    # 返回:OK
    
    # 消费者读取消息
    XREADGROUP GROUP order_group consumer1 COUNT 1 STREAMS orders:stream >
    # 返回:同上消息内容
    

10. 发布/订阅(Pub/Sub)

  • 用途:消息广播(如实时通知、聊天室)。

  • 常用命令

    • PUBLISH channel message:发布消息到频道。
    • SUBSCRIBE channel:订阅频道。
  • 示例

    SUBSCRIBE news_updates     # 订阅新闻频道
    PUBLISH news_updates "Redis 7.0 released!"  # 发布新闻
    
  • 场景 1:实时通知

    # 订阅新闻频道
    SUBSCRIBE news
    # 返回:
    # 1) "subscribe"
    # 2) "news"
    # 3) (integer) 1
    
    # 发布新闻
    PUBLISH news "Redis 7.0 released!"
    # 订阅者接收:
    # 1) "message"
    # 2) "news"
    # 3) "Redis 7.0 released!"
    
  • 场景 2:多频道订阅

    # 订阅多个频道
    PSUBSCRIBE news.*
    # 发布到 news.tech
    PUBLISH news.tech "New Redis features"
    # 订阅者接收:
    # 1) "pmessage"
    # 2) "news.*"
    # 3) "news.tech"
    # 4) "New Redis features"
    

总结

通过以上示例,可以得出如下总结:

数据结构 典型场景 核心命令
String 缓存、计数器 SET, GET, INCR
Hash 对象存储 HSET, HGET, HGETALL
List 消息队列、最新列表 LPUSH, RPOP, LRANGE
Set 标签、共同好友 SADD, SMEMBERS, SINTER
Sorted Set 排行榜、优先级任务 ZADD, ZRANGE, ZREVRANGE
GEO 地理位置查询 GEOADD, GEORADIUS
Bitmap 用户签到、布尔统计 SETBIT, GETBIT, BITCOUNT
HyperLogLog 大数据去重计数 PFADD, PFCOUNT
Stream 消息队列(支持消费者组) XADD, XREAD, XGROUP
Pub/Sub 实时消息广播 PUBLISH, SUBSCRIBE

通过合理选择数据结构和命令,可以高效解决缓存、实时统计、消息通信等多样化需求。