go操作redis的一些练习

使用go-redis

github.com/go-redis/redis

初始化连接

// 初始化连接
// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
    // 注意这里不用 :=   必须给全局变量赋值!
    rdb = redis.NewClient(&redis.Options{
        Addr:     "localhost:6388",
        Password: "", // no password set
        DB:       1,  // use DB 1
    })

    _, err = rdb.Ping().Result()
    if err != nil {
        return err
    }
    return nil
}
View Code

基本的set/get示例

// 基本的 set/get 示例
func setGetDemo(rdb *redis.Client) error {
    // set
    err := rdb.Set("age1", 100, 0).Err()
    if err != nil {
        return err
    }

    // get
    if val, err := rdb.Get("age1").Result(); err != nil {
        return err
    } else {
        fmt.Printf("age1>>> %v  %T \n", val, val) // 100  string
    }

    // get 一个不存在的key的情况
    if val, err := rdb.Get("xxx").Result(); err == redis.Nil {
        fmt.Printf("没有这个key! %s \n", "xxx")
    } else if err != nil {
        return err
    } else {
        fmt.Println("xxx>>> ", val)
    }

    return nil
}
View Code

zset(有序集合)示例

// zset(有序集合)示例
func zsetDemo(rdb *redis.Client) error {
    zsetKey := "scoreRank"

    scoreLst := []redis.Z{
        {Score: 100.0, Member: "Math"},
        {Score: 90.0, Member: "Chinese"},
        {Score: 80.0, Member: "English"},
    }
    // 1 ZAdd 打散传参数
    if num, err := rdb.ZAdd(zsetKey, scoreLst...).Result(); err != nil {
        return err
    } else {
        fmt.Printf("zadd %d succ... \n", num)
    }
    // 2 给English的分数加30
    if newScore, err := rdb.ZIncrBy(zsetKey, 30, "English").Result(); err != nil {
        return err
    } else {
        fmt.Printf("English's score is %f Now! \n", newScore)
    }
    // 3 获取分数最高的3个 注意是闭区间!!!
    if ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result(); err != nil {
        return err
    } else {
        fmt.Println("分数最高的3个:")
        for _, val := range ret {
            fmt.Printf("%s : %f \n", val.Member, val.Score)
        }
    }
    // 获取 Score在 95~110 范围的 (还是闭区间)!
    op := redis.ZRangeBy{
        Min: "95",
        Max: "110",
    }
    if ret, err := rdb.ZRangeByScoreWithScores(zsetKey, op).Result(); err != nil {
        return err
    } else {
        fmt.Println("95~110范围的:")
        for _, val := range ret {
            fmt.Printf("%s : %f \n", val.Member, val.Score)
            /*
                95~110范围的:
                Math : 100.000000
                English : 110.000000
            */
        }
    }
    return nil
}
View Code

pipeline操作

// pipeline的操作
func pipelineDemo(rdb *redis.Client) error {
    // 1 Pipeline示例 ———— 批量set三个key
    pipe := rdb.Pipeline()
    statusCmd1 := pipe.Set("name1", "whw", 0)
    statusCmd2 := pipe.Set("name2", "naruto", 0)
    statusCmd3 := pipe.Set("name3", "sasuke", 0)

    fmt.Println("statusCmd1>>> ", statusCmd1)
    fmt.Println("statusCmd2>>> ", statusCmd2)
    fmt.Println("statusCmd3>>> ", statusCmd3)
    // Exec() !!!
    _, err := pipe.Exec()
    if err != nil {
        return err
    }

    // 2 PipeLined示例 —— 给 pipelined_counter 自增1并且设置超时时间为3600秒!
    var incr *redis.IntCmd
    _, err = rdb.Pipelined(func(pipe redis.Pipeliner) error {
        incr = pipe.Incr("pipelined_counter")
        pipe.Expire("pipelined_counter", time.Hour)
        return nil
    })
    fmt.Println(incr.Val(), err)
    return nil
}
View Code

事务的操作

// 事务的操作
func affairDemo(rdb *redis.Client) error {
    // TxPipeline
    pipe := rdb.TxPipeline()

    incr := pipe.Incr("tx_pipeline_counter")
    pipe.Expire("tx_pipeline_counter", time.Hour)

    _, err := pipe.Exec()
    fmt.Println(incr.Val(), err)

    // TxPipelined
    var incr1 *redis.IntCmd
    _, err = rdb.TxPipelined(func(pipe redis.Pipeliner) error {
        incr1 = pipe.Incr("tx_pipelined_counter")
        pipe.Expire("tx_pipelined_counter", time.Hour)
        return nil
    })
    fmt.Println(incr.Val(), err)
    return nil
}
View Code

完整的代码 ***

package main

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

// 初始化连接
// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
    // 注意这里不用 :=   必须给全局变量赋值!
    rdb = redis.NewClient(&redis.Options{
        Addr:     "localhost:6388",
        Password: "", // no password set
        DB:       1,  // use DB 1
    })

    _, err = rdb.Ping().Result()
    if err != nil {
        return err
    }
    return nil
}

// 基本的 set/get 示例
func setGetDemo(rdb *redis.Client) error {
    // set
    err := rdb.Set("age1", 100, 0).Err()
    if err != nil {
        return err
    }

    // get
    if val, err := rdb.Get("age1").Result(); err != nil {
        return err
    } else {
        fmt.Printf("age1>>> %v  %T \n", val, val) // 100  string
    }

    // get 一个不存在的key的情况
    if val, err := rdb.Get("xxx").Result(); err == redis.Nil {
        fmt.Printf("没有这个key! %s \n", "xxx")
    } else if err != nil {
        return err
    } else {
        fmt.Println("xxx>>> ", val)
    }

    return nil
}

// zset(有序集合)示例
func zsetDemo(rdb *redis.Client) error {
    zsetKey := "scoreRank"

    scoreLst := []redis.Z{
        {Score: 100.0, Member: "Math"},
        {Score: 90.0, Member: "Chinese"},
        {Score: 80.0, Member: "English"},
    }
    // 1 ZAdd 打散传参数
    if num, err := rdb.ZAdd(zsetKey, scoreLst...).Result(); err != nil {
        return err
    } else {
        fmt.Printf("zadd %d succ... \n", num)
    }
    // 2 给English的分数加30
    if newScore, err := rdb.ZIncrBy(zsetKey, 30, "English").Result(); err != nil {
        return err
    } else {
        fmt.Printf("English's score is %f Now! \n", newScore)
    }
    // 3 获取分数最高的3个 注意是闭区间!!!
    if ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result(); err != nil {
        return err
    } else {
        fmt.Println("分数最高的3个:")
        for _, val := range ret {
            fmt.Printf("%s : %f \n", val.Member, val.Score)
        }
    }
    // 获取 Score在 95~110 范围的 (还是闭区间)!
    op := redis.ZRangeBy{
        Min: "95",
        Max: "110",
    }
    if ret, err := rdb.ZRangeByScoreWithScores(zsetKey, op).Result(); err != nil {
        return err
    } else {
        fmt.Println("95~110范围的:")
        for _, val := range ret {
            fmt.Printf("%s : %f \n", val.Member, val.Score)
            /*
                95~110范围的:
                Math : 100.000000
                English : 110.000000
            */
        }
    }
    return nil
}

// pipeline的操作
func pipelineDemo(rdb *redis.Client) error {
    // 1 Pipeline示例 ———— 批量set三个key
    pipe := rdb.Pipeline()
    statusCmd1 := pipe.Set("name1", "whw", 0)
    statusCmd2 := pipe.Set("name2", "naruto", 0)
    statusCmd3 := pipe.Set("name3", "sasuke", 0)

    fmt.Println("statusCmd1>>> ", statusCmd1)
    fmt.Println("statusCmd2>>> ", statusCmd2)
    fmt.Println("statusCmd3>>> ", statusCmd3)
    // Exec() !!!
    _, err := pipe.Exec()
    if err != nil {
        return err
    }

    // 2 PipeLined示例 —— 给 pipelined_counter 自增1并且设置超时时间为3600秒!
    var incr *redis.IntCmd
    _, err = rdb.Pipelined(func(pipe redis.Pipeliner) error {
        incr = pipe.Incr("pipelined_counter")
        pipe.Expire("pipelined_counter", time.Hour)
        return nil
    })
    fmt.Println(incr.Val(), err)
    return nil
}


// 事务的操作
func affairDemo(rdb *redis.Client) error {
    // TxPipeline
    pipe := rdb.TxPipeline()

    incr := pipe.Incr("tx_pipeline_counter")
    pipe.Expire("tx_pipeline_counter", time.Hour)

    _, err := pipe.Exec()
    fmt.Println(incr.Val(), err)

    // TxPipelined
    var incr1 *redis.IntCmd
    _, err = rdb.TxPipelined(func(pipe redis.Pipeliner) error {
        incr1 = pipe.Incr("tx_pipelined_counter")
        pipe.Expire("tx_pipelined_counter", time.Hour)
        return nil
    })
    fmt.Println(incr.Val(), err)
    return nil
}


func main() {
    // 初始化连接
    err := initClient()
    if err != nil {
        panic(fmt.Sprintf("初始化连接失败:%s \n", err.Error()))
    }
    fmt.Println("初始化连接成功......")

    // set/get 练习
    err = setGetDemo(rdb)
    if err != nil {
        panic(fmt.Sprintf("set/get发生错误:%s \n", err.Error()))
    }

    // zset 练习
    err = zsetDemo(rdb)
    if err != nil {
        panic(fmt.Sprintf("zset发生错误:%s \n", err.Error()))
    }

    // pipeline 练习
    err = pipelineDemo(rdb)
    if err != nil {
        panic(fmt.Sprintf("pipeline发生错误:%s \n", err.Error()))
    }

    // 事务练习
    err = affairDemo(rdb)
    if err != nil{
        panic(fmt.Sprintf("事务操作发生错误:%s \n", err.Error()))
    }

}
View Code

使用GET和SET命令以事务方式递增Key的值的示例

const routineCount = 100

increment := func(key string) error {
    txf := func(tx *redis.Tx) error {
        // 获得当前值或零值
        n, err := tx.Get(key).Int()
        if err != nil && err != redis.Nil {
            return err
        }

        // 实际操作(乐观锁定中的本地操作)
        n++

        // 仅在监视的Key保持不变的情况下运行
        _, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
            // pipe 处理错误情况
            pipe.Set(key, n, 0)
            return nil
        })
        return err
    }

    for retries := routineCount; retries > 0; retries-- {
        err := rdb.Watch(txf, key)
        if err != redis.TxFailedErr {
            return err
        }
        // 乐观锁丢失
    }
    return errors.New("increment reached maximum number of retries")
}

var wg sync.WaitGroup
wg.Add(routineCount)
for i := 0; i < routineCount; i++ {
    go func() {
        defer wg.Done()

        if err := increment("counter3"); err != nil {
            fmt.Println("increment error:", err)
        }
    }()
}
wg.Wait()

n, err := rdb.Get("counter3").Int()
fmt.Println("ended with", n, err)
View Code

参考博客

https://www.liwenzhou.com/posts/Go/go_redis/

 

posted on 2020-12-16 16:35  江湖乄夜雨  阅读(164)  评论(0编辑  收藏  举报