go-redis快速入门教程(附仓库源码)

唐裕
2023-12-01

最近整理了go-redis的各种使用方法,直接上代码:

// 获取go-redis包,redis 7对应 v9,redis 6 对应 v8,查看版本的命令
redis-server -v
Redis server v=7.0.9 sha=00000000:0 malloc=libc bits=64 build=62b81c2a663dd6ff
// 本人版本是reidis 7 ,所以使用 v9
// 先在项目根目录添加 go-redis包
go get github.com/redis/go-redis/v9

源代码:https://gitee.com/golibec/go-demo.git

package main

import (
    "context"
    "fmt"
    "time"

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

var rdb *redis.Client

func init() {
    // redis 连接
    rdb = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // 密码
        DB:       0,  // 数据库号
    })

}

func main() {
    //上下文
    ctx := context.Background()

    // -------------------- String 类型 ----------------------

    // 【Set】设置key value 第三个参数 0 表示不过期
    string_res, err := rdb.Set(ctx, "key1", "value1", 0).Result()
    if err != nil {
        panic(string_res)
    }
    fmt.Println(string_res) // OK

    // 【Set】设置一分钟过期
    string_res, err = rdb.Set(ctx, "key2", "value2", time.Minute).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(string_res) // OK

    //  下文为了精简代码,忽略错误处理部分,实际项目代码需要加上
    // 【Get】获取key对应的value
    string_res, _ = rdb.Get(ctx, "key1").Result()
    fmt.Println(string_res) // value1

    // 【GetSet】设置一个key值,并返回这个key的旧值
    string_res, _ = rdb.GetSet(ctx, "key1", "value1_new").Result()
    fmt.Println(string_res) // value1

    // 【SetNX】如果key 不存在,则设置其值,不存在返回true, 已存在返回false
    bool_res, _ := rdb.SetNX(ctx, "key3", "value3", 0).Result()
    fmt.Println(bool_res) // true or false

    // 【MGet】批量查询key的值,返回数组
    array_res, _ := rdb.MGet(ctx, "key1", "key2", "key3").Result()
    fmt.Println(array_res) // [value1_new value2 value3]

    // 【MSet】批量设置key4、key5的值,常规方式
    string_res, _ = rdb.MSet(ctx, "key4", "value4", "key5", "value5").Result()
    fmt.Println(string_res) // OK

    // 【MSet】批量设置key4、key5的值,数组方式
    string_res, _ = rdb.MSet(ctx, []string{"key4", "value4", "key5", "value5"}).Result()
    fmt.Println(string_res) // OK

    // 【MSet】批量设置key4、key5的值,map方式
    string_res, _ = rdb.MSet(ctx, map[string]any{"key4": "value4", "key5": "value5"}).Result()
    fmt.Println(string_res) // OK

    // 【Incr】数值自增,key必须是数值或者不存在
    int64_res, _ := rdb.Incr(ctx, "key6").Result()
    fmt.Println(int64_res) // 1

    // 【IncrBy】数值自增,自定义增步长,key必须是数值或者不存在,每次减2
    int64_res, _ = rdb.IncrBy(ctx, "key7", -2).Result()
    fmt.Println(int64_res) // -2

    // 【IncrByFloat】数值自增,自定义增步长(浮点数),key必须是数值或者不存在
    float64_res, _ := rdb.IncrByFloat(ctx, "key8", 6.23).Result()
    fmt.Println(float64_res) // 6.23

    // 【Decr】数值自减,key必须是数值或者不存在
    int64_res, _ = rdb.Decr(ctx, "key9").Result()
    fmt.Println(int64_res) // -1

    // 【DecrBy】数值自减,自定义步长,key必须是数值或者不存在
    int64_res, _ = rdb.DecrBy(ctx, "key10", 100).Result()
    fmt.Println(int64_res) // -100

    // 【Del】单个删除数
    int64_res, _ = rdb.Del(ctx, "key10").Result()
    fmt.Println(int64_res) // 1

    // 【Del】多个key批量删除,返回删除key 的个数
    int64_res, _ = rdb.Del(ctx, "key9", "key8", "key7", "key6").Result()
    fmt.Println(int64_res) // 4

    // 【Expire】设置key的过期时间,key不存在返回false,设置10秒过期
    bool_res, _ = rdb.Expire(ctx, "key1", time.Second*10).Result()
    fmt.Println(bool_res) // true

    // 【Exists】返回key存在的个数
    int64_res, _ = rdb.Exists(ctx, "key2", "key3", "key55").Result()
    fmt.Println(int64_res) // 2

    // -------------------- Hash 类型 ----------------------

    // 【HSet】为hash key 设置字段名和值,返回不存在的field数
    int64_res, _ = rdb.HSet(ctx, "hkey1", "name", "zhangsan").Result()
    fmt.Println(int64_res) // 1

    // 【HSet】批量设置,数组模式
    int64_res, _ = rdb.HSet(ctx, "hkey1", []string{"sex", "man", "age", "18"}).Result()
    fmt.Println(int64_res) // 2

    // 【HSet】批量设置, map模式
    int64_res, _ = rdb.HSet(ctx, "hkey1", map[string]any{"name": "wangwu", "age": 100}).Result()
    fmt.Println(int64_res) // 0

    // 【HGet】获取 key 指定字段的值
    string_res, _ = rdb.HGet(ctx, "hkey1", "name").Result()
    fmt.Println(string_res) // wangwu

    // 【HGetAll】获取 key 的所有字段和值,返回 map[string]string
    map_res, _ := rdb.HGetAll(ctx, "hkey1").Result()
    fmt.Println(map_res) // map[age:100 name:wangwu sex:man]

    // 【HIncrBy】使 key 指定的字段自增 某个整数值
    int64_res, _ = rdb.HIncrBy(ctx, "hkey1", "count", 1).Result()
    fmt.Println(int64_res) // 1

    // 【HIncrByFloat】使 key 指定的字段自增 某个浮点数值
    float64_res, _ = rdb.HIncrByFloat(ctx, "hkey1", "count", 2.2).Result()
    fmt.Println(float64_res) // 2.2

    // 【HKeys】返回 key 的所有字段名,返回数组
    array_string_res, _ := rdb.HKeys(ctx, "hkey1").Result()
    fmt.Println(array_string_res) // [age name sex score count]

    // 【HLen】返回 key 的所有字段的总数
    int64_res, _ = rdb.HLen(ctx, "hkey1").Result()
    fmt.Println(int64_res) // 5

    // 【HMGet】获取 key 指定字段(多个)的值
    array_res, _ = rdb.HMGet(ctx, "hkey1", "name", "age", "score").Result()
    fmt.Println(array_res) // [wangwu 100 1]

    // 【HMSet】批量设置, map模式
    bool_res, _ = rdb.HMSet(ctx, "hkey1", map[string]any{"name": "zhaoliu", "age": 33}).Result()
    fmt.Println(bool_res) // true

    // 【HSetNX】如果字段不存在,则设置值
    bool_res, _ = rdb.HSetNX(ctx, "hkey1", "name", "da da da").Result()
    fmt.Println(bool_res) // false

    // 【HDel】删除 key 的指定字段(支持批量),返回删除字段的个数
    int64_res, _ = rdb.HDel(ctx, "hkey1", "name", "age").Result()
    fmt.Println(int64_res) // 2

    // 【HExists】检查 key 的指定字段是否存在
    bool_res, _ = rdb.HExists(ctx, "hkey1", "score").Result()
    fmt.Println(bool_res) // true

    // -------------------- List 类型 ----------------------

    // 【LPush】从左边插入数据,支持一次插入任意个数据,返回数据的总数
    int64_res, _ = rdb.LPush(ctx, "lkey1", "one", "two", "three", "four").Result()
    fmt.Println(int64_res) // 4

    // 【LPushX】用法与上述一样,但只有列表存在时才插入
    int64_res, _ = rdb.LPushX(ctx, "lkey2", "one", "two").Result()
    fmt.Println(int64_res) // 0

    // 【RPop】从列表的右边删除数据,并返回删除的数据
    string_res, _ = rdb.RPop(ctx, "lkey1").Result()
    fmt.Println(string_res) // one

    // 【RPush】、【RPushX】、【LPop】与上述对应,反向相反,不再示例

    // 【LLen】返回列表元素的总数
    int64_res, _ = rdb.LLen(ctx, "lkey1").Result()
    fmt.Println(int64_res) // 3

    // 【LRange】返回列表某范围的元素,开始索引为0,-1表示到末尾
    array_string_res, _ = rdb.LRange(ctx, "lkey1", 1, -1).Result()
    fmt.Println(array_string_res) // [three two]

    // 【LRem】从列表左边开始删除指定元素, 返回结果为成功删除的个数
    //  1表示删除从左边开始遇到的1个 two;
    //  如果是-2表示删除从右边开始遇到的两个two
    //  如果为 0 表示删除列表中的所有 two
    int64_res, _ = rdb.LRem(ctx, "lkey1", 1, "two").Result()
    fmt.Println(int64_res) // 1

    // 再插入一些测试数据
    rdb.LPush(ctx, "lkey1", "five", "six", "seven", "eight").Result()

    // 【LIndex】返回指定索引位置的元素(左侧索引从0开始)
    string_res, _ = rdb.LIndex(ctx, "lkey1", 3).Result()
    fmt.Println(string_res) // five

    // 【LInsert】在指定位置插入元素, before为指定元素之前, after为之后
    //  返回插入之后元素的数量,指定元素不存在返回 -1
    int64_res, _ = rdb.LInsert(ctx, "lkey1", "before", "six", "before_one").Result()
    fmt.Println(int64_res) // 7

    // -------------------- Set 类型 ----------------------
    //  与List 类型的区别是集合中的元素不能重复,已存在则不添加

    // 【SAdd】添加元素,支持批量,返回添加成功的个数
    int64_res, _ = rdb.SAdd(ctx, "skey1", 100, 100, 200, 300, 400, 500, 600).Result()
    fmt.Println(int64_res) // 6  两个100只算1个

    // 【SCard】获取集合元素个数
    int64_res, _ = rdb.SCard(ctx, "skey1").Result()
    fmt.Println(int64_res) // 6

    // 【SIsMember】判断元素是否在集合中
    bool_res, _ = rdb.SIsMember(ctx, "skey1", 500).Result()
    fmt.Println(bool_res) // true

    // 【SMembers】获取集合中的所有元素
    array_string_res, _ = rdb.SMembers(ctx, "skey1").Result()
    fmt.Println(array_string_res) // [100 200 300 400 500 600]

    // 【SRem】删除集合中的元素,返回被删元素的个数
    int64_res, _ = rdb.SRem(ctx, "skey1", 100, 200).Result()
    fmt.Println(int64_res) // 2

    // 【SPop】随机删除1个元素,并返回删除的元素
    string_res, _ = rdb.SPop(ctx, "skey1").Result()
    fmt.Println(string_res) // 500

    // 【SPop】随机删除n个元素,并返回删除的元素数组
    array_string_res, _ = rdb.SPopN(ctx, "skey1", 2).Result()
    fmt.Println(array_string_res) // [400 300]

    // -------------------- Sorted Set 类型 ----------------------
    //  带排序的集合,Score 为排序的权重值
    // 【ZAdd】添加元素,支持批量,返回成功添加的个数,元素存在则更新分数
    int64_res, _ = rdb.ZAdd(ctx, "zkey1",
        redis.Z{
            Score:  9.2,
            Member: "one",
        },
        redis.Z{
            Score:  8.3,
            Member: "two",
        },
        redis.Z{
            Score:  7.3,
            Member: "three",
        },
    ).Result()
    fmt.Println(int64_res) // 3

    // 【ZCount】返回指定分数区间的元素个数(注意要用字符串),返回 7 <= 分数 <= 9的元素个数
    //  后两个参数如果是 "(7" , "(9" 则表示 7 < 分数 < 9
    int64_res, _ = rdb.ZCount(ctx, "zkey1", "7", "9").Result()
    fmt.Println(int64_res) // 2

    // 【ZIncrBy】给指定元素增加分数
    float64_res, _ = rdb.ZIncrBy(ctx, "zkey1", 2.2, "one").Result()
    fmt.Println(float64_res) // 11.399999999999999

    // 【ZRange】按分数从小到大返回元素集合,索引范围, -1表示全部
    array_string_res, _ = rdb.ZRange(ctx, "zkey1", 0, -1).Result()
    fmt.Println(array_string_res) // [three two one]

    // 【ZRevRange】按分数大到小返回元素集合,索引范围, -1表示全部
    array_string_res, _ = rdb.ZRevRange(ctx, "zkey1", 0, 1).Result()
    fmt.Println(array_string_res) // [one two]

    // 【ZRangeByScore】按分数从小到大返回元素集合, 索引范围,分数范围
    op := redis.ZRangeBy{
        Min:    "(5", // > 5
        Max:    "9",  // <= 9
        Offset: 0,    // 类似mysql的  偏移位置
        Count:  5,    // 类似mysql的 limit 数量
    }
    array_string_res, _ = rdb.ZRangeByScore(ctx, "zkey1", &op).Result()
    fmt.Println(array_string_res) // [three two]

    // 【ZRevRangeByScore】按分数从大到小返回元素集合, 索引范围,分数范围
    array_string_res, _ = rdb.ZRevRangeByScore(ctx, "zkey1", &op).Result()
    fmt.Println(array_string_res) // [two three]

    // 【ZRangeByScoreWithScores】同时返回元素和分数,从小到大
    array_struct_res, _ := rdb.ZRangeByScoreWithScores(ctx, "zkey1", &op).Result()
    fmt.Println(array_struct_res) // [{7.3 three} {8.3 two}]

    // 【ZRevRangeByScoreWithScores】同时返回元素和分数,从大到小
    array_struct_res, _ = rdb.ZRevRangeByScoreWithScores(ctx, "zkey1", &op).Result()
    fmt.Println(array_struct_res) // [{8.3 two} {7.3 three}]

    // 【ZRem】删除集合元素,支持批量,返回成功删除的个数
    int64_res, _ = rdb.ZRem(ctx, "zkey1", "one", "two").Result()
    fmt.Println(int64_res) // 2

    // 【ZRemRangeByRank】按索引范围删除,返回成功删除的个数
    int64_res, _ = rdb.ZRemRangeByRank(ctx, "zkey1", 0, 1).Result()
    fmt.Println(int64_res) // 1

    // 【ZRemRangeByScore】按分数范围删除,返回成功删除的个数
    int64_res, _ = rdb.ZRemRangeByScore(ctx, "zkey1", "(2", "8").Result()
    fmt.Println(int64_res) // 0

    rdb.ZAdd(ctx, "zkey1",
        redis.Z{
            Score:  1.1,
            Member: "one",
        },
        redis.Z{
            Score:  2.2,
            Member: "two",
        },
        redis.Z{
            Score:  3.3,
            Member: "three",
        },
    ).Result()

    // 【ZScore】查询指定元素的分数,不存在返回0
    float64_res, _ = rdb.ZScore(ctx, "zkey1", "one").Result()
    fmt.Println(float64_res) // 0

    // 【ZRank】查询指定元素从小到大的排名,索引从0开始
    int64_res, _ = rdb.ZRank(ctx, "zkey1", "two").Result()
    fmt.Println(int64_res) // 1

    // 【ZRevRank】查询指定元素从大到小的排名,索引从0开始
    int64_res, _ = rdb.ZRevRank(ctx, "zkey1", "one").Result()
    fmt.Println(int64_res) // 2

    // -------------------- 事务处理 ----------------------
    // 类似于mysql事务,事务中的所有命令会按顺序执行,并且不被外界命令所打断
    // 原子性:要么全部执行,要么全部不执行
    // 【TxPipeline】开启一个事务
    pipe := rdb.TxPipeline()
    p := pipe.Set(ctx, "pkey1", 1, 0)
    pipe.IncrBy(ctx, "pkey1", 2)
    // 【Exec】执行事务,这一步之后才开始顺序执行所有命令
    res, err := pipe.Exec(ctx)
    fmt.Println(res, err) // [set pkey1 1: OK incrby pkey1 2: 3] <nil>
    fmt.Println(p.Val())  // OK

    // -------------------- 消息订阅 ----------------------
    Subscribe()

    select {}
}

// 订阅
func Subscribe() {
    // 模拟发布者,每两秒往频道里发送1次消息
    go func() {
        ctx := context.Background()
        c := time.Tick(time.Second * 2)
        var count int
        for {
            <-c
            count++
            // 【Publish】往指定频道发送消息
            rdb.Publish(ctx, "channel1", fmt.Sprintf("hello: %d", count))
        }
    }()

    var receive func(int) = func(num int) {
        ctx := context.Background()
        //【Subscribe】订阅频道
        sub := rdb.Subscribe(ctx, "channel1")
        // 订阅者实时接收频道中的消息
        for msg := range sub.Channel() {
            // 打印频道号和消息内容
            fmt.Printf("我是接收者%d,我接收到来自频道%s的消息: %s\n",
                num, msg.Channel, msg.Payload)
        }

    }

    // 模拟接收者1
    go receive(1)
    // 模拟接收者2
    go receive(2)

}

 类似资料: