Go 常用包: 操作 redis 開源庫 -go-redis-
- 介紹
redis官網推薦使用redigo(https://github.com/gomodule/redigo),截止到今天Github Start是8.2k 但go-redis(https://github.com/go-redis/redis)使用的人更多, 並且go-redis封裝得更好。截止到今天Github Start 是12.1k。
- 安裝
2.1 歷史版本
go get -u github.com/go-redis/redis
2.2 最新版本
go get github.com/go-redis/redis/v8
@注意: 最新版本的客戶端在操作 redis 時,相關函數需要傳遞上下文 (context.Context), 以下內容都是基於最新版本。
- 連接
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
}
}
- 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
}
- 基本鍵值操作
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
*/
- 列表 (
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