Skip to content

Go 客户端基础 ​

本章介绍 go-redis 客户端的基本使用,包括连接、配置和常用操作。

安装 ​

bash
go get github.com/redis/go-redis/v9

连接客户端 ​

基本连接 ​

go
package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

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

    ctx := context.Background()

    // 测试连接
    pong, err := rdb.Ping(ctx).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(pong)  // PONG
}

完整配置 ​

go
rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    Password:     "",
    DB:           0,
    PoolSize:     10,
    MinIdleConns: 5,
    MaxRetries:   3,
    DialTimeout:  5 * time.Second,
    ReadTimeout:  3 * time.Second,
    WriteTimeout: 3 * time.Second,
})

集群连接 ​

go
rdb := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs: []string{
        "node1:6379",
        "node2:6379",
        "node3:6379",
    },
    Password: "",
})

基本操作 ​

String 操作 ​

go
ctx := context.Background()

// Set
err := rdb.Set(ctx, "key", "value", 0).Err()

// Set with TTL
rdb.Set(ctx, "key", "value", 10*time.Minute)

// Get
val, err := rdb.Get(ctx, "key").Result()
if err == redis.Nil {
    fmt.Println("key does not exist")
}

// SetNX
ok, _ := rdb.SetNX(ctx, "lock", "owner", 10*time.Second).Result()

// MSet/MGet
rdb.MSet(ctx, "key1", "value1", "key2", "value2")
vals, _ := rdb.MGet(ctx, "key1", "key2").Result()

// Incr/Decr
rdb.Incr(ctx, "counter")
rdb.IncrBy(ctx, "counter", 10)
rdb.Decr(ctx, "counter")

Hash 操作 ​

go
// HSet
rdb.HSet(ctx, "user:1001", "name", "Alice")
rdb.HSet(ctx, "user:1001", map[string]interface{}{
    "age":   25,
    "email": "alice@example.com",
})

// HGet
name, _ := rdb.HGet(ctx, "user:1001", "name").Result()

// HGetAll
fields, _ := rdb.HGetAll(ctx, "user:1001").Result()

// HDel
rdb.HDel(ctx, "user:1001", "age")

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

List 操作 ​

go
// LPush/RPush
rdb.LPush(ctx, "mylist", "value1")
rdb.RPush(ctx, "mylist", "value2")

// LRange
vals, _ := rdb.LRange(ctx, "mylist", 0, -1).Result()

// LPop/RPop
val, _ := rdb.LPop(ctx, "mylist").Result()

// LLen
len, _ := rdb.LLen(ctx, "mylist").Result()

// BRPop (阻塞)
result, _ := rdb.BRPop(ctx, 0, "mylist").Result()

Set 操作 ​

go
// SAdd
rdb.SAdd(ctx, "myset", "member1", "member2")

// SMembers
members, _ := rdb.SMembers(ctx, "myset").Result()

// SIsMember
isMember, _ := rdb.SIsMember(ctx, "myset", "member1").Result()

// SRem
rdb.SRem(ctx, "myset", "member1")

// SInter
intersection, _ := rdb.SInter(ctx, "set1", "set2").Result()

ZSet 操作 ​

go
// ZAdd
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 100, Member: "user1"})

// ZRange
members, _ := rdb.ZRange(ctx, "leaderboard", 0, -1).Result()

// ZRangeWithScores
membersWithScores, _ := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Result()

// ZScore
score, _ := rdb.ZScore(ctx, "leaderboard", "user1").Result()

// ZRank
rank, _ := rdb.ZRevRank(ctx, "leaderboard", "user1").Result()

高级特性 ​

Pipeline ​

批量执行命令,减少网络往返。

go
pipe := rdb.Pipeline()

cmd1 := pipe.Get(ctx, "key1")
cmd2 := pipe.Get(ctx, "key2")
cmd3 := pipe.Get(ctx, "key3")

_, err := pipe.Exec(ctx)
if err != nil {
    panic(err)
}

fmt.Println(cmd1.Val(), cmd2.Val(), cmd3.Val())

事务 ​

go
err := rdb.Watch(ctx, func(tx *redis.Tx) error {
    n, err := tx.Get(ctx, "key").Int64()
    if err != nil && err != redis.Nil {
        return err
    }

    _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
        pipe.Set(ctx, "key", n+1, 0)
        return nil
    })
    return err
}, "key")

Pub/Sub ​

go
// 订阅
pubsub := rdb.Subscribe(ctx, "channel1", "channel2")

// 接收消息
for msg := range pubsub.Channel() {
    fmt.Println(msg.Channel, msg.Payload)
}

// 发布
rdb.Publish(ctx, "channel1", "message")

Scan ​

遍历键。

go
var cursor uint64
for {
    var keys []string
    var err error
    keys, cursor, err = rdb.Scan(ctx, cursor, "user:*", 10).Result()
    if err != nil {
        panic(err)
    }

    for _, key := range keys {
        fmt.Println(key)
    }

    if cursor == 0 {
        break
    }
}

错误处理 ​

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

val, err := rdb.Get(ctx, "key").Result()
if err != nil {
    if err == redis.Nil {
        fmt.Println("key does not exist")
    } else {
        fmt.Println("error:", err)
    }
    return
}

最佳实践 ​

  1. 使用连接池:PoolSize 和 MinIdleConns
  2. 设置超时:DialTimeout、ReadTimeout、WriteTimeout
  3. 使用 Pipeline:批量操作减少网络往返
  4. 合理设置 TTL:避免内存泄漏
  5. 错误处理:区分键不存在和其他错误

在下一章中,我们将学习 Redis 的持久化机制。