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 }
基本的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 }
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 }
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 }
事务的操作
// 事务的操作 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 }
完整的代码 ***
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())) } }
使用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)
参考博客
https://www.liwenzhou.com/posts/Go/go_redis/