Go 常用包: 操作 redis 開源庫 -go-redis-

  1. 介紹

redis官網推薦使用redigo(https://github.com/gomodule/redigo),截止到今天Github Start是8.2kgo-redis(https://github.com/go-redis/redis)使用的人更多, 並且go-redis封裝得更好。截止到今天Github Start 是12.1k

  1. 安裝

2.1 歷史版本

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

2.2 最新版本

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

@注意: 最新版本的客戶端在操作 redis 時,相關函數需要傳遞上下文 (context.Context), 以下內容都是基於最新版本。

  1. 連接Redis

3.1 單機連接 (NewClient)

// 單機連接redis
func TestConnect(t *testing.T) {
 client := redis.NewClient(&redis.Options{
  Addr: "127.0.0.1:6379",
 })
 // 檢測是否建立連接(需要傳遞上下文)
 timeoutCtx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
 defer cancelFunc()
 // 檢測
 _, err := client.Ping(timeoutCtx).Result()
 if err != nil {
  t.Error(err)
    return
 }
}

3.2 哨兵模式連接 (NewFailoverClient)

// 哨兵模式連接
func TestConnectSentinel(t *testing.T) {
 client := redis.NewFailoverClient(&redis.FailoverOptions{
  MasterName:    "master-name",
  SentinelAddrs: []string{":9126"":9127"":9128"},
 })
 // 檢測是否建立連接(需要傳遞上下文)
 timeoutCtx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
 defer cancelFunc()
 // 檢測
 _, err := client.Ping(timeoutCtx).Result()
 if err != nil {
  t.Error(err)
  return
 }
}

3.3 集羣模式連接 (NewClusterClient)

// 集羣模式連接
func TestConnectCluster(t *testing.T) {
 client := redis.NewClusterClient(&redis.ClusterOptions{
  Addrs: []string{":7000"":7001"":7002"":7003"},
 })
 // 檢測是否建立連接(需要傳遞上下文)
 timeoutCtx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
 defer cancelFunc()
 // 檢測
 _, err := client.Ping(timeoutCtx).Result()
 if err != nil {
  t.Error(err)
  return
 }
}
  1. redis.Options 參數詳解

type Options struct {
  // 網絡類型:tcp|unix 默認:tcp
 Network string
  
 // redis地址,格式 host:port
 Addr string
  
  // 當新建一個redis連接的時候,會回調這個函數
 OnConnect func(ctx context.Context, cn *Conn) error
  
  // 指定用戶名連接(從redis6.0版本或更高以上支持)
 Username string
  
 // redis密碼,可以爲空。
 Password string
  
  // redis數據庫,範圍:0~15,默認是0,可以爲空
 DB int
  
  // 最大重試次數,默認是3次,-1:表示關閉
 MaxRetries int
  
 // 最小重試時間間隔,默認是 8ms ; -1 表示關閉.
 MinRetryBackoff time.Duration
  
 // 最大重試時間間隔.默認是 512ms; -1 表示關閉.
 MaxRetryBackoff time.Duration

 // redis連接超時時間.默認是 5 秒.
 DialTimeout time.Duration
  
 // 讀取超時時間,默認3秒.
 ReadTimeout time.Duration
  
 // 寫入超時時間,默認和ReadTimeout一致
 WriteTimeout time.Duration

  // redis最大連接數,默認連接池大小等於 runtime.GOMAXPROCS(cpu個數) * 10
 PoolSize int
  
 // 啓動時,創建最小空閒連接數
 MinIdleConns int
  
 // redis連接最大的存活時間,默認不會關閉過時的連接.
 MaxConnAge time.Duration
  
  // 當從redis連接池獲取一個連接之後,連接池最多等待這個拿出去的連接多長時間。
 // 默認是等待 ReadTimeout + 1 秒.
 PoolTimeout time.Duration
  
 // redis連接池多久會關閉一個空閒連接.
 // 默認是 5 分鐘. -1 則表示關閉這個配置項
 IdleTimeout time.Duration
  
  // 多長時間檢測一下,空閒連接
 // 默認是 1 分鐘. -1 表示關閉空閒連接檢測
 IdleCheckFrequency time.Duration

 // 設置只讀模式,如果設置爲true redis只能查不能更新
 readOnly bool

  // 限流接口
 Limiter Limiter
}
  1. 基本鍵值操作

5.1 設置和獲取

1. 單值操作: Set和Get

// Get&Set
func TestGetAndSet(t *testing.T) {
 // 參考上面的單機模式連接redis
 client, err := goredis.ConnectSingle()
 if err != nil {
  t.Error(err)
  return
 }
 ctx := context.Background()
 // 設置緩存
 key := "test:abc"
 err = client.Set(ctx, key, "hello word!", time.Minute*10).Err()
 if err != nil {
  t.Error("設置緩存失敗"+err.Error())
  return
 }
 // 獲取緩存
 result, err := client.Get(ctx, key).Result()
 if err != nil {
  t.Error("獲取緩存失敗"+err.Error())
  return
 }
 fmt.Println("獲取結果: ",result)
}
/*** 輸出
=== RUN   TestGetAndSet
獲取結果:  hello word!
--- PASS: TestGetAndSet (0.01s)
PASS
*/

2. 批量操作: MSet和MGet

// 批量設置和獲取
func TestMGetSet(t *testing.T) {
 // 連接redis
 client, _ := goredis.ConnectSingle()
 ctx := context.Background()
 // MSet: 同時設置一個或多個 key-value 對。
 err := client.MSet(ctx, "key1""val1""key2""val2""key3""val3").Err()
 if err != nil {
  t.Error(err)
  return
 }
 // 使用Get獲取緩存
 for _, key := range []string{"key1","key2","key3"} {
  result, _ := client.Get(ctx, key).Result()
  fmt.Printf("Get獲取,鍵: %s 值: %v \n",key,result)
 }
 // 使用MGet獲取
 result, _ := client.MGet(ctx, "key1""key2","key3").Result()
 fmt.Println("MGet批量獲取:",result)
}

/**輸出
=== RUN   TestMGetSet
Get獲取,鍵: key1 值: val1 
Get獲取,鍵: key2 值: val2 
Get獲取,鍵: key3 值: val3 
MGet批量獲取: [val1 val2 val3]
--- PASS: TestMGetSet (0.01s)
PASS
*/

5.2 鎖 ( SetNX)

// SetNX: 指定的 key 不存在時,爲 key 設置指定的值
func TestSetNx(t *testing.T) {
 // 連接redis
 client, err := goredis.ConnectSingle()
 if err != nil {
  t.Error(err)
  return
 }
 ctx := context.Background()
 for i := 0; i < 3; i++ {
  res, err := client.SetNX(ctx, "abc", time.Now().Unix(), time.Hour).Result()
  if err != nil {
   t.Error(err)
   break
  }
  fmt.Println("SetNX abc success :", res)
 }
}
/** 輸出
=== RUN   TestSetNx
SetNX abc success : true
SetNX abc success : false
SetNX abc success : false
--- PASS: TestSetNx (0.01s)
PASS
*/

5.3 自增自減

// 自增和自減
func TestIncrAndDecr(t *testing.T) {
 // 連接redis
 client, _ := goredis.ConnectSingle()
 ctx := context.Background()
 // 自增
 for i := 1; i <= 5; i++ {
  // Incr: 每次調用+1
  client.Incr(ctx,"incr1")
  // IncrBy: 每次調用+5
  client.IncrBy(ctx,"incr2",5)
  // IncrByFloat: 每次調用 +0.5
  client.IncrByFloat(ctx,"incr3",0.5)
  // 查詢緩存
  result, _ := client.MGet(ctx, "incr1""incr2""incr3").Result()
  fmt.Printf("第%d次自增後查詢: %v \n",i,result)
 }
 // 自減
 for i := 1; i <= 5; i++ {
  // Decr: 每次調用-1
  client.Decr(ctx,"decr1")
  // DecrBy: 每次調用-5
  client.DecrBy(ctx,"decr2",5)
  // 查詢緩存
  result, _ := client.MGet(ctx, "decr1""decr2").Result()
  fmt.Printf("第%d次自減後查詢: %v \n",i,result)
 }
}

/**輸出
=== RUN   TestIncrAndDecr
第1次自增後查詢: [10 50 5] 
第2次自增後查詢: [11 55 5.5] 
第3次自增後查詢: [12 60 6] 
第4次自增後查詢: [13 65 6.5] 
第5次自增後查詢: [14 70 7] 
第1次自減後查詢: [-5 -25] 
第2次自減後查詢: [-6 -30] 
第3次自減後查詢: [-7 -35] 
第4次自減後查詢: [-8 -40] 
第5次自減後查詢: [-9 -45] 
--- PASS: TestIncrAndDecr (0.08s)
PASS
*/

5.4 刪除和追加

// 刪除和追加
func TestDelAndAppend(t *testing.T) {
 client, _ := goredis.ConnectSingle()
 ctx := context.Background()
  // ========== 刪除測試 ==========
 // 刪除單個
 client.Del(ctx,"key1")
 // 刪除多個
 client.Del(ctx,"incr1","incr2","incr3")

 // ======== 追加value 測試使用 ========
 client.Set(ctx,"key","hello",time.Hour)
 // 獲取值
 res1, _ := client.Get(ctx,"key").Result()
 fmt.Println("追加前的值:",res1)
 // 追加
 client.Append(ctx,"key"," word")
 res2, _ := client.Get(ctx,"key").Result()
 fmt.Println("追加後的值:",res2)
}
/**輸出
=== RUN   TestDelAndAppend
追加前的值: hello
追加後的值: hello word
--- PASS: TestDelAndAppend (0.02s)
PASS
*/
  1. 列表 (List) 操作

6.1 插入

func TestInsertList(t *testing.T) {
 // 連接redis
 client, _ := ConnectSingle()
 ctx := context.Background()
 key := "insertList"
 //從列表頭部插入,不存在則新建並插入數據
 for _, val := range []string{"php""go"} {
  // 插入頭部(左邊)
  client.LPush(ctx, key, val)
  // 獲取
  result, _ := client.LRange(ctx, key, 0, -1).Result()
  fmt.Printf("LPush 從頭部插入【%v】: %v\n", val,result)
 }
 // 從列表尾部插入
 for _,val := range []string{"張三","李四"} {
  // 插入尾部(右邊)
  client.RPush(ctx, key, val)
  // 獲取
  result, _ := client.LRange(ctx, key, 0, -1).Result()
  fmt.Printf("RPush 從尾部插入【%v】: %v\n", val,result)
 }
 result, _ := client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("當前列表所有值: %+v\n", result)

 // 在指定的值前插入
 client.LInsertBefore(ctx,key,"php","php5.6")
 result, _ = client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("在php前插入%v,當前列表所有值: %v\n""php5.6",result)
 // 在指定的值後插入
 client.LInsertAfter(ctx,key,"go","go1.0")
 result, _ = client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("在go後插入%v,當前列表所有值: %v\n""go1.0",result)
}
/**輸出
=== RUN   TestInsertList
LPush 從頭部插入【php】: [php]
LPush 從頭部插入【go】: [go php]
RPush 從尾部插入【張三】: [go php 張三]
RPush 從尾部插入【李四】: [go php 張三 李四]
當前列表所有值: [go php 張三 李四]
在php前插入php5.6,當前列表所有值: [go php5.6 php 張三 李四]
在go後插入go1.0,當前列表所有值: [go go1.0 php5.6 php 張三 李四]
--- PASS: TestInsertList (0.04s)
PASS
*/

6.2 讀取

func TestReadList(t *testing.T) {
 // 連接redis
 client, _ := ConnectSingle()
 ctx := context.Background()
 key := "language-list"
 // 插入元素
 client.LPush(ctx, key, "php""go""java""c""c++""python")
 fmt.Println("插入列表: ""php""go""java""c""c++""python")
 // 獲取長度
 result, _ := client.LLen(ctx, key).Result()
 fmt.Println("列表長度: ", result)
 // =========獲取指定key的值=======
 val, _ := client.LIndex(ctx, key, 0).Result()
 fmt.Println("獲取索引爲0的值: ", val)

 // =========獲取指定範圍的值=======
 // 獲取[0,2]的元素
 strings, _ := client.LRange(ctx, key, 0, 2).Result()
 fmt.Printf("獲取列表位置爲[0,2]的元素:%v\n", strings)
 // 獲取全部元素[0,-1]
 all, _ := client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("獲取列表所有[0,-1]元素:%v\n", all)
}
/**輸出
=== RUN   TestReadList
插入列表:  php go java c c++ python
列表長度:  6
獲取索引爲0的值:  python
獲取列表位置爲[0,2]的元素:[python c++ c]
獲取列表所有[0,-1]元素:[python c++ c java go php]
--- PASS: TestReadList (0.02s)
PASS
*/

6.3 刪除

func TestDelList(t *testing.T)  {
 // 連接redis
 client, _ := ConnectSingle()
 ctx := context.Background()
 key := "language-list"
 // 插入元素
 client.LPush(ctx, key, "php""go""java""c""c++""python")
 all, _ := client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("當前列表所有值:%v\n", all)

 // 移出並獲取列表的第一個元素
 first, _ := client.LPop(ctx, key).Result()
 fmt.Printf("LPop,移出並獲取列表的第一個元素:%v\n", first)
 // 當前列表所有值
 all, _ = client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("當前列表所有值:%v\n", all)
 // 移出並獲取列表的最後一個元素
 last, _ := client.RPop(ctx, key).Result()
 fmt.Printf("RPop,移出並獲取列表的最後一個元素:%v\n", last)
 // 當前列表所有值
 all, _ = client.LRange(ctx, key, 0, -1).Result()
 fmt.Printf("當前列表所有值:%v\n", all)
}
/** 輸出
=== RUN   TestDelList
當前列表所有值:[python c++ c java go php]
LPop,移出並獲取列表的第一個元素:python
當前列表所有值:[c++ c java go php]
RPop,移出並獲取列表的最後一個元素:php
當前列表所有值:[c++ c java go]
--- PASS: TestDelList (0.02s)
PASS
*/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/j80wPHpetN4OtyGy-gCykA