Skip to content

数据类型与操作 ​

Redis 支持丰富的数据类型,每种类型都有特定的应用场景和操作命令。

String(字符串) ​

String 是最基本的数据类型,可以存储字符串、整数、浮点数或二进制数据。

基本操作 ​

bash
# 设置值
SET key value
SET user:1001 "Alice"

# 获取值
GET user:1001

# 设置值并设置过期时间(秒)
SETEX session:token 3600 "user_data"

# 设置值(仅当 key 不存在)
SETNX lock:resource "locked"

# 批量设置
MSET key1 value1 key2 value2

# 批量获取
MGET key1 key2

数值操作 ​

bash
# 设置数值
SET counter 100

# 递增
INCR counter        # 101
INCRBY counter 10   # 111

# 递减
DECR counter        # 110
DECRBY counter 10   # 100

# 浮点数递增
SET price 10.50
INCRBYFLOAT price 2.5  # 13.0

字符串操作 ​

bash
# 追加字符串
SET msg "Hello"
APPEND msg " World"  # "Hello World"

# 获取子串
GETRANGE msg 0 4     # "Hello"

# 设置子串
SETRANGE msg 6 "Redis"  # "Hello Redis"

# 获取长度
STRLEN msg           # 11

Go 客户端示例 ​

go
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/redis/go-redis/v9"
)

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    ctx := context.Background()

    // 设置值
    err := rdb.Set(ctx, "user:1001", "Alice", 0).Err()
    if err != nil {
        panic(err)
    }

    // 获取值
    val, err := rdb.Get(ctx, "user:1001").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("user:1001 =", val)

    // 设置带过期时间
    rdb.Set(ctx, "session:token", "abc123", 1*time.Hour)

    // 递增计数
    rdb.Incr(ctx, "page:views")

    // 批量操作
    rdb.MSet(ctx, "key1", "value1", "key2", "value2")
    vals, _ := rdb.MGet(ctx, "key1", "key2").Result()
    fmt.Println(vals)
}

应用场景 ​

  • 缓存:存储 JSON、HTML 等数据
  • 计数器:页面访问、点赞数
  • 分布式锁:SET NX EX
  • 会话:存储用户会话信息

Hash(哈希) ​

Hash 是一个键值对集合,适合存储对象。

基本操作 ​

bash
# 设置字段
HSET user:1001 name "Alice"
HSET user:1001 age 25
HSET user:1001 email "alice@example.com"

# 获取字段
HGET user:1001 name

# 获取所有字段
HGETALL user:1001

# 获取多个字段
HMGET user:1001 name age

# 设置多个字段
HMSET user:1002 name "Bob" age 30

# 删除字段
HDEL user:1001 age

# 检查字段是否存在
HEXISTS user:1001 name

# 获取所有字段名
HKEYS user:1001

# 获取所有值
HVALS user:1001

# 获取字段数量
HLEN user:1001

数值操作 ​

bash
# 字段递增
HSET user:1001 score 100
HINCRBY user:1001 score 10    # 110
HINCRBYFLOAT user:1001 score 5.5  # 115.5

Go 客户端示例 ​

go
func hashExample(rdb *redis.Client) {
    ctx := context.Background()

    // 设置单个字段
    rdb.HSet(ctx, "user:1001", "name", "Alice")
    rdb.HSet(ctx, "user:1001", "age", 25)

    // 设置多个字段
    rdb.HSet(ctx, "user:1001", map[string]interface{}{
        "email": "alice@example.com",
        "city":  "Beijing",
    })

    // 获取单个字段
    name, _ := rdb.HGet(ctx, "user:1001", "name").Result()
    fmt.Println("name:", name)

    // 获取所有字段
    fields, _ := rdb.HGetAll(ctx, "user:1001").Result()
    for k, v := range fields {
        fmt.Printf("%s: %s\n", k, v)
    }

    // 递增
    rdb.HIncrBy(ctx, "user:1001", "age", 1)
}

应用场景 ​

  • 对象存储:用户信息、商品信息
  • 计数器:每个用户的多种计数
  • 购物车:商品ID和数量

List(列表) ​

List 是有序的字符串列表,支持从两端插入和弹出。

基本操作 ​

bash
# 左侧插入
LPUSH mylist "world"
LPUSH mylist "hello"

# 右侧插入
RPUSH mylist "redis"

# 获取列表长度
LLEN mylist

# 获取范围内的元素
LRANGE mylist 0 -1    # 所有元素

# 获取指定索引的元素
LINDEX mylist 0

# 设置指定索引的元素
LSET mylist 0 "HELLO"

# 左侧弹出
LPOP mylist

# 右侧弹出
RPOP mylist

# 阻塞弹出(用于消息队列)
BLPOP mylist 0
BRPOP mylist 0

列表操作 ​

bash
# 裁剪列表
LTRIM mylist 0 99    # 只保留前100个

# 在指定元素前后插入
LINSERT mylist BEFORE "world" "there"
LINSERT mylist AFTER "world" "!"

# 移除指定值的元素
LREM mylist 1 "value"

# 将元素从一个列表移到另一个列表
RPOPLPUSH srclist dstlist

Go 客户端示例 ​

go
func listExample(rdb *redis.Client) {
    ctx := context.Background()

    // 插入元素
    rdb.LPush(ctx, "mylist", "world")
    rdb.LPush(ctx, "mylist", "hello")
    rdb.RPush(ctx, "mylist", "redis")

    // 获取列表长度
    len, _ := rdb.LLen(ctx, "mylist").Result()
    fmt.Println("length:", len)

    // 获取所有元素
    vals, _ := rdb.LRange(ctx, "mylist", 0, -1).Result()
    fmt.Println("elements:", vals)

    // 弹出元素
    val, _ := rdb.LPop(ctx, "mylist").Result()
    fmt.Println("popped:", val)

    // 阻塞弹出(消息队列)
    result, _ := rdb.BRPop(ctx, 0, "task_queue").Result()
    fmt.Println("task:", result[1])
}

应用场景 ​

  • 消息队列:LPUSH + BRPOP
  • 最新列表:LTRIM 保留最新 N 条
  • 时间线:最新动态、朋友圈

Set(集合) ​

Set 是无序的字符串集合,自动去重。

基本操作 ​

bash
# 添加元素
SADD myset "member1"
SADD myset "member2" "member3"

# 获取所有元素
SMEMBERS myset

# 检查元素是否存在
SISMEMBER myset "member1"

# 移除元素
SREM myset "member1"

# 获取集合大小
SCARD myset

# 随机获取元素
SRANDMEMBER myset

# 随机弹出元素
SPOP myset

集合运算 ​

bash
# 交集
SINTER set1 set2

# 并集
SUNION set1 set2

# 差集
SDIFF set1 set2

# 将运算结果存储到新集合
SINTERSTORE result set1 set2
SUNIONSTORE result set1 set2
SDIFFSTORE result set1 set2

Go 客户端示例 ​

go
func setExample(rdb *redis.Client) {
    ctx := context.Background()

    // 添加元素
    rdb.SAdd(ctx, "tags:article:1", "redis", "database", "nosql")

    // 检查元素是否存在
    isMember, _ := rdb.SIsMember(ctx, "tags:article:1", "redis").Result()
    fmt.Println("is member:", isMember)

    // 获取所有元素
    members, _ := rdb.SMembers(ctx, "tags:article:1").Result()
    fmt.Println("members:", members)

    // 集合运算
    rdb.SAdd(ctx, "tags:article:2", "redis", "cache", "performance")

    // 交集
    intersection, _ := rdb.SInter(ctx, "tags:article:1", "tags:article:2").Result()
    fmt.Println("intersection:", intersection)  // [redis]
}

应用场景 ​

  • 标签系统:文章标签、用户兴趣
  • 社交关系:共同好友、推荐好友
  • 去重:已访问URL、已投票用户

ZSet(有序集合) ​

ZSet 是有序的字符串集合,每个元素关联一个分数。

基本操作 ​

bash
# 添加元素
ZADD leaderboard 100 "user1"
ZADD leaderboard 95 "user2"
ZADD leaderboard 98 "user3"

# 获取元素分数
ZSCORE leaderboard "user1"

# 获取排名(从低到高)
ZRANK leaderboard "user1"

# 获取排名(从高到低)
ZREVRANK leaderboard "user1"

# 获取元素数量
ZCARD leaderboard

# 获取分数范围内的元素数量
ZCOUNT leaderboard 90 100

# 递增分数
ZINCRBY leaderboard 5 "user1"

范围查询 ​

bash
# 按排名范围获取(从低到高)
ZRANGE leaderboard 0 9 WITHSCORES

# 按排名范围获取(从高到低)
ZREVRANGE leaderboard 0 9 WITHSCORES

# 按分数范围获取
ZRANGEBYSCORE leaderboard 90 100 WITHSCORES

# 按分数范围删除
ZREMRANGEBYSCORE leaderboard 0 50

Go 客户端示例 ​

go
func zsetExample(rdb *redis.Client) {
    ctx := context.Background()

    // 添加元素
    rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 100, Member: "user1"})
    rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 95, Member: "user2"})
    rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 98, Member: "user3"})

    // 获取排名(从高到低)
    rank, _ := rdb.ZRevRank(ctx, "leaderboard", "user1").Result()
    fmt.Println("rank:", rank)  // 0

    // 获取 Top 10
    members, _ := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Result()
    for i, z := range members {
        fmt.Printf("%d. %s: %.1f\n", i+1, z.Member, z.Score)
    }

    // 按分数范围查询
    vals, _ := rdb.ZRangeByScore(ctx, "leaderboard", &redis.ZRangeBy{
        Min: "90",
        Max: "100",
    }).Result()
    fmt.Println("90-100:", vals)
}

应用场景 ​

  • 排行榜:游戏排名、热搜榜
  • 延时队列:时间戳作为分数
  • 带权重的队列:优先级队列

其他数据类型 ​

Bitmap(位图) ​

bash
# 设置位
SETBIT mykey 0 1
SETBIT mykey 1 0

# 获取位
GETBIT mykey 0

# 统计位为1的数量
BITCOUNT mykey

# 位运算
BITOP AND result key1 key2

应用:用户签到、在线状态统计

HyperLogLog ​

bash
# 添加元素
PFADD visitors user1 user2 user3

# 获取基数(不重复元素数量)
PFCOUNT visitors

# 合并
PFMERGE result visitors1 visitors2

应用:UV 统计、去重计数

Stream ​

bash
# 添加消息
XADD mystream * field1 value1

# 读取消息
XREAD COUNT 2 STREAMS mystream 0

# 创建消费者组
XGROUP CREATE mystream mygroup $

# 消费消息
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >

应用:消息队列、事件流

数据类型选择 ​

场景推荐类型原因
简单缓存String简单高效
对象存储Hash字段独立操作
列表数据List有序、支持队列
去重集合Set自动去重
排行榜ZSet自动排序
签到统计Bitmap节省空间
UV统计HyperLogLog空间占用小

总结 ​

掌握 Redis 的数据类型和操作是使用 Redis 的基础。在下一章中,我们将学习 Go 客户端的使用。