1. 程式人生 > >Go操作Redis實戰

Go操作Redis實戰

[TOC] ## 安裝Redis客戶端 Go語言中使用第三方庫https://github.com/go-redis/redis連線Redis資料庫並進行操作。使用以下命令下載並安裝: ```shell go get github.com/go-redis/redis/v8 ``` > 注:匯入時指定了版本v8,忽略版本是一個常見錯誤 ### 連線redis > 說明:Background返回一個非空的Context。 它永遠不會被取消,沒有值,也沒有期限。 它通常在main函式,初始化和測試時使用,並用作傳入請求的頂級上下文。 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) //Background返回一個非空的Context。 它永遠不會被取消,沒有值,也沒有期限。 //它通常在main函式,初始化和測試時使用,並用作傳入請求的頂級上下文。 var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) pong, err := rdb.Ping(ctx).Result() if err != nil { fmt.Printf("連線redis出錯,錯誤資訊:%v", err) } fmt.Println("成功連線redis") } ``` ## 基本指令 ### Keys():根據正則獲取keys 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //*表示獲取所有的key keys, err := rdb.Keys(ctx, "*").Result() if err != nil { panic(err) } fmt.Println(keys) } ``` ### Type():獲取key對應值得型別 `Type()`方法使用者獲取一個key對應值的型別 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) vType, err := rdb.Type(ctx, "key").Result() if err != nil { panic(err) } fmt.Println(vType) //string } ``` ### Del():刪除快取項 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) n, err := rdb.Del(ctx, "key1", "key2").Result() if err != nil { panic(err) } fmt.Printf("成功刪除了 %v 個\n", n) } ``` ### Exists():檢測快取項是否存在 `Exists()`方法用於檢測某個key是否存在 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) n, err := rdb.Exists(ctx, "key1").Result() if err != nil { panic(err) } if n > 0 { fmt.Println("存在") } else { fmt.Println("不存在") } } ``` > 注:Exists()方法可以傳入多個key,返回的第一個結果表示存在的key的數量,不過工作中我們一般不同時判斷多個key是否存在,一般就判斷一個key,所以判斷是否大於0即可,如果判斷判斷傳入的多個key是否都存在,則返回的結果的值要和傳入的key的數量相等 ### Expire(),ExpireAt():設定有效期 需要在設定好了快取項後,在設定有效期 `Expire()`方法是設定某個時間段(time.Duration)後過期,`ExpireAt()`方法是在某個時間點(time.Time)過期失效 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" "time" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.Expire(ctx, "key", time.Minute * 2).Result() if err != nil { panic(err) } if res { fmt.Println("設定成功") } else { fmt.Println("設定失敗") } res, err = rdb.ExpireAt(ctx, "key2", time.Now()).Result() if err != nil { panic(err) } if res { fmt.Println("設定成功") } else { fmt.Println("設定失敗") } } ``` ### TTL(),PTTL():獲取有效期 `TTL()`方法可以獲取某個鍵的剩餘有效期 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" "time" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //設定一分鐘的有效期 rdb.Expire(ctx, "key", time.Minute) //獲取剩餘有效期,單位:秒(s) ttl, err := rdb.TTL(ctx, "key").Result() if err != nil { panic(err) } fmt.Println(ttl) //獲取剩餘有效期,單位:毫秒(ms) pttl, err := rdb.PTTL(ctx, "key").Result() if err != nil { panic(err) } fmt.Println(pttl) } ``` ### DBSize():檢視當前資料庫key的數量 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) num, err := rdb.DBSize(ctx).Result() if err != nil { panic(err) } fmt.Printf("資料庫有 %v 個快取項\n", num) } ``` ### FlushDB():清空當前資料 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //清空當前資料庫,因為連線的是索引為0的資料庫,所以清空的就是0號資料庫 res, err := rdb.FlushDB(ctx).Result() if err != nil { panic(err) } fmt.Println(res)//OK } ``` ### FlushAll():清空所有資料庫 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.FlushAll(ctx).Result() if err != nil { panic(err) } fmt.Println(res)//OK } ``` ## 字串(string)型別 ### Set():設定 僅僅支援字串(包含數字)操作,不支援內建資料編碼功能。如果需要儲存Go的非字串型別,需要提前手動序列化,獲取時再反序列化。 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" "time" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) _, err := rdb.Ping(ctx).Result() //fmt.Println(pong, err) if err != nil { fmt.Printf("連線redis出錯,錯誤資訊:%v", err) return } //Set方法的最後一個引數表示過期時間,0表示永不過期 err = rdb.Set(ctx, "key1", "value1", 0).Err() if err != nil { panic(err) } //key2將會在兩分鐘後過期失效 err = rdb.Set(ctx, "key2", "value2", time.Minute * 2).Err() if err != nil { panic(err) } } ``` ### SetEX():設定並指定過期時間 設定鍵的同時,設定過期時間 示例: ```go package main import ( "context" "github.com/go-redis/redis/v8" "time" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) err := rdb.SetEX(ctx, "key", "value", time.Hour * 2).Err() if err != nil { panic(err) } } ``` ### SetNX():設定並指定過期時間 > 注:SetNX()與SetEX()的區別是,SexNX()僅當key不存在的時候才設定,如果key已經存在則不做任何操作,而SetEX()方法不管該key是否已經存在快取中直接覆蓋 介紹了`SetNX()`與`SetEX()`的區別後,還有一點需要注意的時候,如果我們想知道我們呼叫SetNX()是否設定成功了,可以接著呼叫Result()方法,返回的第一個值表示是否設定成功了,如果返回false,說明快取Key已經存在,此次操作雖然沒有錯誤,但是是沒有起任何效果的。如果返回true,表示在此之前key是不存在快取中的,操作是成功的 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" "time" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.SetNX(ctx, "key", "value", time.Minute).Result() if err != nil { panic(err) } if res { fmt.Println("設定成功") } else { fmt.Printf("key已經存在快取中,設定失敗") } } ``` ### Get():獲取 如果要獲取的key在快取中並不存在,`Get()`方法將會返回`redis.Nil` 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) err := rdb.Set(ctx, "key", "value", 0).Err() if err != nil { panic(err) } val, err := rdb.Get(ctx, "key").Result() if err != nil { panic(err) } fmt.Printf("key: %v\n", val) val2, err := rdb.Get(ctx, "key-not-exist").Result() if err == redis.Nil { fmt.Println("key不存在") } else if err != nil { panic(err) } else { fmt.Printf("值為: %v\n", val2) } } ``` ### GetRange():字串擷取 `GetRange()`方法可以用來擷取字串的部分內容,第二個引數是下標索引的開始位置,第三個引數是下標索引的結束位置(不是要擷取的長度) 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) err := rdb.Set(ctx, "key", "Hello World!", 0).Err() if err != nil { panic(err) } val, err := rdb.GetRange(ctx, "key", 1, 4).Result() if err != nil { panic(err) } fmt.Printf("key: %v\n", val) //擷取到的內容為: ello } ``` > 注:即使key不存在,呼叫GetRange()也不會報錯,只是返回的擷取結果是空"",可以使用fmt.Printf("%q\n", val)來列印測試 ### Incr():增加+1 `Incr()`、`IncrBy()`都是運算元字,對數字進行增加的操作,incr是執行`原子`加1操作,incrBy是增加指定的數 所謂原子操作是指不會被執行緒排程機制打斷的操作:這種操作一旦開始,就一直執行到結束,中間不會有任何context witch(切換到另一個執行緒). (1)在單執行緒中,能夠在單條指令中完成的操作都可以認為是“原子操作”,因為中斷只能發生於指令之間。 (2)在多執行緒中,不能被其它程序(執行緒)打算的操作叫原子操作。 Redis單命令的原子性主要得益於Redis的單執行緒 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.Incr(ctx, "number").Result() if err != nil { panic(err) } fmt.Printf("key當前的值為: %v\n", val) } ``` ### IncrBy():按指定步長增加 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.IncrBy(ctx, "number", 12).Result() if err != nil { panic(err) } fmt.Printf("key當前的值為: %v\n", val) } ``` ### Decr():減少-1 `Decr()`和`DecrBy()`方法是對數字進行減的操作,和Incr正好相反 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.Decr(ctx, "number").Result() if err != nil { panic(err) } fmt.Printf("key當前的值為: %v\n", val) } ``` ### DecrBy():按指定步長減少 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.DecrBy(ctx, "number", 12).Result() if err != nil { panic(err) } fmt.Printf("key當前的值為: %v\n", val) } ``` ### Append():追加 `Append()`表示往字串後面追加元素,返回值是字串的總長度 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) err := rdb.Set(ctx, "key", "hello", 0).Err() if err != nil { panic(err) } length, err := rdb.Append(ctx, "key", " world!").Result() if err != nil { panic(err) } fmt.Printf("當前快取key的長度為: %v\n", length) //12 val, err := rdb.Get(ctx, "key").Result() if err != nil { panic(err) } fmt.Printf("當前快取key的值為: %v\n", val) //hello world! } ``` ### StrLen():獲取長度 `StrLen()`方法可以獲取字串的長度 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) err := rdb.Set(ctx, "key", "hello world!", 0).Err() if err != nil { panic(err) } length, err := rdb.StrLen(ctx, "key").Result() if err != nil { panic(err) } fmt.Printf("當前快取key的長度為: %v\n", length) //12 } ``` 如上所述都是常用的字串操作,此外,字串(string)型別還有`MGet()`、`Mset()`、`MSetNX()`等同時操作多個key的方法,詳見:https://pkg.go.dev/github.com/go-redis/redis/v8 ## 列表(list)型別 ### LPush():將元素壓入連結串列 可以使用`LPush()`方法將資料從左側壓入連結串列 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //返回值是當前列表元素的數量 n, err := rdb.LPush(ctx, "list", 1, 2, 3).Result() if err != nil { panic(err) } fmt.Println(n) } ``` 也可以從右側壓如連結串列,對應的方法是`RPush()` ### LInsert():在某個位置插入新元素 位置的判斷,是根據相對的參考元素判斷 示例: ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //在名為key的快取項值為100的元素前面插入一個值,值為123 err := rdb.LInsert(ctx, "key", "before", "100", 123).Err() if err != nil { panic(err) } } ``` > 注:即使key列表裡有多個值為100的元素,也只會在第一個值為100的元素前面插入123,並不會在所有值為100的前面插入123,客戶端還提供了從前面插入和從後面插入的LInsertBefore()和LInsertAfer()方法 ### LSet():設定某個元素的值 示例: ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //下標是從0開始的 err := rdb.LSet(ctx, "list", 1, 100).Err() if err != nil { panic(err) } } ``` ### LLen():獲取連結串列元素個數 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) length, err := rdb.LLen(ctx, "list").Result() if err != nil { panic(err) } fmt.Printf("當前連結串列的長度為: %v\n", length) } ``` ### LIndex():獲取連結串列下標對應的元素 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.LIndex(ctx, "list", 0).Result() if err != nil { panic(err) } fmt.Printf("下標為0的值為: %v\n", val) } ``` ### LRange():獲取某個選定範圍的元素集 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) vals, err := rdb.LRange(ctx, "list", 0, 2).Result() if err != nil { panic(err) } fmt.Printf("從下標0到下標2的值: %v\n", vals) } ``` ### 從連結串列左側彈出資料 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.LPop(ctx, "list").Result() if err != nil { panic(err) } fmt.Printf("移除的元素為: %v\n", val) } ``` 與之相對的,從右側彈出資料的方法為`RPop()` ### LRem():根據值移除元素 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) n, err := rdb.LRem(ctx, "list", 2, "100").Result() if err != nil { panic(err) } fmt.Printf("移除了: %v 個\n", n) } ``` ## 集合(set)型別 Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要儲存一個列表資料,又不希望出現重複資料,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的介面,這是也是list所不能提供了。 Redis的Set是string型別的無序集合。它底層其實是一個value為null的hash表,所以新增、刪除、查詢的複雜度都是O(1)。 集合資料的特徵: 1. 元素不能重複,保持唯一性 2. 元素無序,不能使用索引(下標)操作 ### SAdd():新增元素 示例: ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.SAdd(ctx, "team", "kobe", "jordan") rdb.SAdd(ctx, "team", "curry") rdb.SAdd(ctx, "team", "kobe") //由於kobe已經被新增到team集合中,所以重複新增時無效的 } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183018843-1310645998.png) ### SPop():隨機獲取一個元素 無序性,是隨機的 `SPop()`方法是從集合中隨機取出元素的,如果想一次獲取多個元素,可以使用`SPopN()`方法 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) val, err := rdb.SPop(ctx, "team").Result() if err != nil { panic(err) } fmt.Println(val) } ``` ### SRem():刪除集合裡指定的值 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) n, err := rdb.SRem(ctx, "team", "kobe", "v2").Result() if err != nil { panic(err) } fmt.Println(n) } ``` ### SSMembers():獲取所有成員 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) vals, err := rdb.SMembers(ctx, "team").Result() if err != nil { panic(err) } fmt.Println(vals) } ``` ### SIsMember():判斷元素是否在集合中 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) exists, err := rdb.SIsMember(ctx, "team", "jordan").Result() if err != nil { panic(err) } if exists { fmt.Println("存在集合中") } else { fmt.Println("不存在集合中") } } ``` ### SCard():獲取集合元素個數 獲取集合中元素個數 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) total, err := rdb.SCard(ctx, "team").Result() if err != nil { panic(err) } fmt.Printf("集合總共有 %v 個元素\n", total) } ``` ### SUnion():並集,SDiff():差集,SInter():交集 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.SAdd(ctx, "setA", "a", "b", "c", "d") rdb.SAdd(ctx, "setB", "a", "d", "e", "f") //並集 union, err := rdb.SUnion(ctx, "setA", "setB").Result() if err != nil { panic(err) } fmt.Println(union) //差集 diff, err := rdb.SDiff(ctx, "setA", "setB").Result() if err != nil { panic(err) } fmt.Println(diff) //交集 inter, err := rdb.SInter(ctx, "setA", "setB").Result() if err != nil { panic(err) } fmt.Println(inter) } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183038266-1015436986.png) ## 有序集合(zset)型別 Redis 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。 不同的是每個元素都會關聯一個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。 有序集合的成員是唯一的,但`分數(score)`卻可以重複。 集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是O(1)。 集合中最大的成員數為 232
- 1 (4294967295, 每個集合可儲存40多億個成員)。 ### ZAdd():新增元素 新增6個元素1~6,分值都是0 ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 1, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 2, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 3, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 4, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 5, }) rdb.ZAdd(ctx, "zSet", &redis.Z{ Score: 0, Member: 6, }) } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183048739-78261498.png) ### ZIncrBy():增加元素分值 分值可以為負數,表示遞減 ```go package main import ( "context" "github.com/go-redis/redis/v8" "math/rand" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "1") rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "2") rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "3") rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "4") rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "5") rdb.ZIncrBy(ctx, "zSet", float64(rand.Intn(100)), "6") } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183058501-610881172.png) ### ZRange()、ZRevRange():獲取根據score排序後的資料段 根據分值排序後的,升序和降序的列表獲取 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //獲取排行榜 //獲取分值(點選率)前三的文章ID列表 res, err := rdb.ZRevRange(ctx, "zSet", 0, 2).Result() if err != nil { panic(err) } fmt.Println(res) } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183107532-961643422.png) ### ZRangeByScore()、ZRevRangeByScore():獲取score過濾後排序的資料段 根據分值過濾之後的列表 需要提供分值區間 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.ZRangeByScore(ctx, "zSet", &redis.ZRangeBy{ Min: "40", Max: "85", }).Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### ZCard():獲取元素個數 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) count, err := rdb.ZCard(ctx, "zSet").Result() if err != nil { panic(err) } fmt.Println(count) } ``` ### ZCount():獲取區間內元素個數 獲取分值在[40, 85]的元素的數量 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) n, err := rdb.ZCount(ctx, "zSet", "40", "85").Result() if err != nil { panic(err) } fmt.Println(n) } ``` ### ZScore():獲取元素的score 獲取元素分值 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) score, err := rdb.ZScore(ctx, "zSet", "5").Result() if err != nil { panic(err) } fmt.Println(score) } ``` ### ZRank()、ZRevRank():獲取某個元素在集合中的排名 `ZRank()`方法是返回元素在集合中的升序排名情況,從0開始。`ZRevRank()`正好相反 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.ZRevRank(ctx, "zSet", "2").Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### ZRem():刪除元素 `ZRem()`方法支援通過元素的值來刪除元素 ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //通過元素值來刪除元素 res, err := rdb.ZRem(ctx, "zSet", "2").Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### ZRemRangeByRank():根據排名來刪除 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //按照升序排序刪除第一個和第二個元素 res, err := rdb.ZRemRangeByRank(ctx, "zSet", 0, 1).Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### ZRemRangeByScore():根據分值區間來刪除 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) //刪除score在[40, 70]之間的元素 res, err := rdb.ZRemRangeByScore(ctx, "zSet", "40", "70").Result() if err != nil { panic(err) } fmt.Println(res) } ``` ## 雜湊(hash)型別 Redis hash 是一個 string 型別的 field(欄位) 和 value(值) 的對映表,hash 特別適合用於儲存物件。 Redis 中每個 hash 可以儲存 232
- 1 鍵值對(40多億)。 當前伺服器一般都是將使用者登入資訊儲存到Redis中,這裡儲存使用者登入資訊就比較適合用hash表。hash表比string更合適,如果我們選擇使用string型別來儲存使用者的資訊的時候,我們每次儲存的時候就得先序列化(json\_encode()、serialize())成字串才能儲存redis, 從redis拿到使用者資訊後又得反序列化(UnMarshal()、Marshal())成陣列或物件,這樣開銷比較大。如果使用hash的話我們通過key(使用者ID)+field(屬性標籤)就可以操作對應屬性資料了,既不需要重複儲存資料,也不會帶來序列化和併發修改控制的問題。 ### HSet():設定 `HSet()`方法支援如下格式 ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.HSet(ctx, "user", "key1", "value1", "key2", "value2") rdb.HSet(ctx, "user", []string{"key3", "value3", "key4", "value4"}) rdb.HSet(ctx, "user", map[string]interface{}{"key5": "value5", "key6": "value6"}) } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183214584-776904066.png) ### HMset():批量設定 示例: ```go package main import ( "context" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) rdb.Del(ctx, "user") rdb.HMSet(ctx, "user", map[string]interface{}{"name":"kevin", "age": 27, "address":"北京"}) } ``` ![](https://img2020.cnblogs.com/blog/720430/202012/720430-20201227183222667-1708717111.png) ### HGet():獲取某個元素 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) address, err := rdb.HGet(ctx, "user", "address").Result() if err != nil { panic(err) } fmt.Println(address) } ``` ### HGetAll():獲取全部元素 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) user, err := rdb.HGetAll(ctx, "user").Result() if err != nil { panic(err) } fmt.Println(user) } ``` ### HDel():刪除某個元素 `HDel()`支援一次刪除多個元素 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.HDel(ctx, "user", "name", "age").Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### HExists():判斷元素是否存在 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.HExists(ctx, "user", "address").Result() if err != nil { panic(err) } fmt.Println(res) } ``` ### HLen():獲取長度 示例: ```go package main import ( "context" "fmt" "github.com/go-redis/redis/v8" ) var ctx = context.Background() func main() { rdb := redis.NewClient(&redis.Options{ Addr: "172.16.147.128:6379", Password: "", DB: 0, }) res, err := rdb.HLen(ctx, "user").Result() if err != nil { panic(err) } fmt.Println(res