参考资料

  1. https://www.runoob.com/redis/redis-transactions.html -菜鸟教程
  2. https://www.liwenzhou.com/posts/Go/go_redis/#autoid-2-4-0 -李文周博客

    安装

    go get -u github.com/go-redis/redis

    连接

    ```go var rdb *redis.Client

func initClient() (err error) { rdb = redis.NewClient(&redis.Options{ Addr: “localhost:6379”, Password: “”, DB: 0, // 默认值 }) _, err = rdb.Ping().Result() return err }

  1. <a name="lSpL6"></a>
  2. # 基本操作
  3. <a name="eE3yP"></a>
  4. ## set、get
  5. ```go
  6. func main() {
  7. err := initClient()
  8. if err != nil {
  9. fmt.Printf("initclinet failed, err: %v\n", err)
  10. }
  11. // key, value , 超时时间
  12. err = rdb.Set("score", 100, 0).Err()
  13. if err != nil {
  14. fmt.Printf("set failed, %v\n", err)
  15. }
  16. val, err := rdb.Get("score").Result()
  17. if err != nil {
  18. fmt.Printf("get failed, %v\n", err)
  19. } else {
  20. fmt.Println(val)
  21. }
  22. val2, err := rdb.Get("name").Result()
  23. if err == redis.Nil {
  24. fmt.Println("name does not exist")
  25. } else if err != nil {
  26. fmt.Printf("get name failed, err:%v\n", err)
  27. return
  28. } else {
  29. fmt.Println("name:", val2)
  30. }
  31. }

zset

  1. func redisExample2() {
  2. zsetKey := "language_rank"
  3. languages := []redis.Z{
  4. redis.Z{Score: 90.0, Member: "Golang"},
  5. redis.Z{Score: 98.0, Member: "Java"},
  6. redis.Z{Score: 95.0, Member: "Python"},
  7. redis.Z{Score: 97.0, Member: "JavaScript"},
  8. redis.Z{Score: 99.0, Member: "C/C++"},
  9. }
  10. // ZADD
  11. num, err := rdb.ZAdd(zsetKey, languages...).Result()
  12. if err != nil {
  13. fmt.Printf("zadd failed, err:%v\n", err)
  14. return
  15. }
  16. fmt.Printf("zadd %d succ.\n", num)
  17. // 把Golang的分数加10
  18. newScore, err := rdb.ZIncrBy(zsetKey, 10.0, "Golang").Result()
  19. if err != nil {
  20. fmt.Printf("zincrby failed, err:%v\n", err)
  21. return
  22. }
  23. fmt.Printf("Golang's score is %f now.\n", newScore)
  24. // 取分数最高的3个
  25. ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result()
  26. if err != nil {
  27. fmt.Printf("zrevrange failed, err:%v\n", err)
  28. return
  29. }
  30. for _, z := range ret {
  31. fmt.Println(z.Member, z.Score)
  32. }
  33. // 取95~100分的
  34. op := redis.ZRangeBy{
  35. Min: "95",
  36. Max: "100",
  37. }
  38. ret, err = rdb.ZRangeByScoreWithScores(zsetKey, op).Result()
  39. if err != nil {
  40. fmt.Printf("zrangebyscore failed, err:%v\n", err)
  41. return
  42. }
  43. for _, z := range ret {
  44. fmt.Println(z.Member, z.Score)
  45. }
  46. }

Pipeline

使用pipeline的目的是进行网络优化:如果有数量很多的redis服务请求,如果每个请求都单独发送,则将耗费大量RTT(Round-Trip Time),而使用pipeline,将使大量请求一次性发送,只耗费一个RTT。

适用场景:
需要连续发送多个相互之间没有依赖的数据库指令。

  1. // 基本操作
  2. pipe := rdb.Pipeline()
  3. incr := pipe.Incr("pipeline_counter")
  4. pipe.Expire("pipeline_counter", time.Hour)
  5. _, err := pipe.Exec()
  6. fmt.Println(incr.Val(), err)
  7. // 使用pipelined
  8. var incr *redis.IntCmd
  9. _, err := rdb.Pipelined(func(pipe redis.Pipeliner) error {
  10. incr = pipe.Incr("pipelined_counter")
  11. pipe.Expire("pipelined_counter", time.Hour)
  12. return nil
  13. })
  14. fmt.Println(incr.Val(), err)
  15. // 相当于一次性执行了下面的命令:
  16. // INCR pipeline_counter
  17. // EXPIRE pipeline_counts 3600

事务

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
  1. pipe := rdb.TxPipeline()
  2. incr := pipe.Incr("tx_pipeline_counter")
  3. pipe.Expire("tx_pipeline_counter", time.Hour)
  4. _, err := pipe.Exec()
  5. fmt.Println(incr.Val(), err)
  6. // 相当于执行了:
  7. // MULTI
  8. // INCR pipeline_counter
  9. // EXPIRE pipeline_counts 3600
  10. // EXEC

watch

在某些场景下,我们除了要使用MULTI/EXEC命令外,还需要配合使用WATCH命令。用户使用WATCH命令监视某个键之后,直到该用户执行EXEC命令的这段时间里,如果有其他用户抢先对被监视的键进行了更改,那么当用户尝试执行EXEC的时候,事务将失败并返回一个错误,用户可以根据这个错误选择重试事务或者放弃事务。

  1. // 监视watch_count的值,并在值不变的前提下将其值+1
  2. key := "watch_count"
  3. err = client.Watch(func(tx *redis.Tx) error {
  4. n, err := tx.Get(key).Int()
  5. if err != nil && err != redis.Nil {
  6. return err
  7. }
  8. _, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
  9. pipe.Set(key, n+1, 0)
  10. return nil
  11. })
  12. return err
  13. }, key)