数据类型与操作
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 # 11Go 客户端示例
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.5Go 客户端示例
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 dstlistGo 客户端示例
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 set2Go 客户端示例
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 50Go 客户端示例
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 客户端的使用。