go-redis
0.基本使用
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
fmt.Println(rdb)
// Redis<localhost:6379 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.Println("key", val) // key value
val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
//key2 does not exist
}
}
1.操作String類型
操作redis String類型
String 類型是 Redis 中最基本的資料類型,string 類型的值最大能存儲 512MB。
下面是go-redis操作String字元串類型的一些API:
- Set:設定字元串的值
- SetEX:設定并指定過期時間(set expire)
- SetNX:設定并指定過期時間(if not exists) 如果key已經存在,則傳回err
- Get:擷取字元串的值
- GetRange:擷取字元串值的子字元
這些API的示範代碼如下:
package main
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// Set 設定
err = rdb.Set(ctx, "key", "thisisavalue", 0).Err() // 0表示永不過期
if err != nil {
panic(err)
}
err = rdb.Set(ctx, "key2", "this is a value2", time.Minute*2).Err() // key2将會在兩分鐘後過期失效
if err != nil {
panic(err)
}
fmt.Println("set success")
// SetEX 設定并指定過期時間
err = rdb.SetEX(ctx, "key3", "this is a value3", time.Hour*2).Err()
if err != nil {
panic(err)
}
fmt.Println("SetEX success")
// SetNX 設定并指定過期時間(如果key已經存在傳回err
_, err = rdb.SetNX(ctx, "key4", "this is a value4", time.Minute).Result()
if err != nil {
fmt.Println("SetNX failed, key4已經存在", err)
}
fmt.Println("SetNX success")
// Get 擷取
result, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key值:", result)
result, err = rdb.Get(ctx, "key5").Result()
// redis.Nil來區分空字元串應答和Nil應答(鍵不存在)
if err == redis.Nil {
fmt.Println("key5不存在")
} else if err != nil {
panic(err)
} else {
fmt.Println("key5值為:", result)
}
// GetRange 擷取字元串值的子字元
result, err = rdb.GetRange(ctx, "key", 1, 4).Result()
if err != nil {
panic(err)
}
fmt.Printf("GetRange截取key值為: %v\n", result)
}
// 列印結果如下:
/*
set success
SetEX success
SetNX success
key值: thisisavalue
key5不存在
GetRange截取key值為: hisi
*/
下面是增減量的API:
- Incr:将 key 中儲存的數字值增加1
- IncrBy:将 key 所儲存的值加上給定的增量值
- Decr:将 key 中儲存的數字值減1
- DecrBy:key 所儲存的值減去給定的減量值
這些API的示範代碼如下:
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// Incr 增加+1
result, err := rdb.Incr(ctx, "count").Result()
if err != nil {
panic(err)
}
fmt.Printf("count值為: %v\n", result)
// IncrBy 按指定步長增加
result, err = rdb.IncrBy(ctx, "count", 2).Result()
if err != nil {
panic(err)
}
fmt.Printf("count值為: %v\n", result)
// Decr 減少-1
result, err = rdb.Decr(ctx, "count").Result()
if err != nil {
panic(err)
}
fmt.Printf("count值為: %v\n", result)
// DecrBy 按指定步長減少
result, err = rdb.DecrBy(ctx, "count", 2).Result()
if err != nil {
panic(err)
}
fmt.Printf("count值為: %v\n", result)
}
// 列印結果如下:
/*
count值為: 1
count值為: 3
count值為: 2
count值為: 0
*/
2.操作List類型
Redis 清單是簡單的字元串清單,按照插入順序排序。可以添加一個元素到清單的頭部(左邊)或者尾部(右邊)。
下面是go-redis操作redis List清單類型的一些API:
- LPush:在清單的左側加入資料
- LLen:擷取連結清單元素個數
- LIndex:擷取清單某下标對應元素
- LInsert:向某個索引位置插入一個元素
- LSet:設定清單某個索引位置的值
- Lpop:從清單左側彈出資料
- LRange:擷取某個索引範圍裡的元素
- LTrim:對一個清單進行修剪,隻讓清單保留指定區間内的元素,不在指定區間之内的元素都将被删除
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
result, err := rdb.Exists(ctx, "test_list").Result()
if err != nil {
return
}
if result == 1{
fmt.Println("test_list have existed ")
value, err := rdb.Del(ctx,"test_list").Result()
if err != nil {
return
}
if value ==1 {
fmt.Println("test_list delete success!")
}
}
// LPush(ctx, key, values...) 在清單的左側加入資料
n, err := rdb.LPush(ctx, "test_list", 1, 2, 3, 4, 5, 6).Result()
if err != nil {
panic(err)
}
fmt.Println(n)
// LLen(ctx, key) 擷取連結清單元素個數
len, err := rdb.LLen(ctx, "test_list").Result()
if err != nil {
panic(err)
}
fmt.Println("test_list的長度:", len)
// LIndex(ctx, key, index) 擷取清單某下标對應元素
val, err := rdb.LIndex(ctx, "test_list", 2).Result() // 索引從0數起。
if err != nil {
panic(err)
}
// 6 5 4 3 2 1
fmt.Println("index是2的值:", val)
// LInsert(ctx, key, op, pivot, value) 向某個索引位置插入一個元素
err = rdb.LInsert(ctx, "test_list", "before", "2", 8).Err() // 在test_list清單的2的前面插入8。
if err != nil {
panic(err)
}
// 6 5 4 3 8 2 1
fmt.Println("插入成功")
// LSet(ctx, key, index, value) 設定清單某個索引位置的值
err = rdb.LSet(ctx, "test_list", 1, 9).Err() // 給索引為1 的位置設定為9。索引從0數起。
if err != nil {
panic(err)
}
fmt.Println("設定成功")
fmt.Println(rdb.LRange(ctx,"test_list",0,-1).Result())
// 6 9 4 3 8 2 1
// LPop(ctx, key) 從清單左側彈出資料
val, err = rdb.LPop(ctx, "test_list").Result()
if err != nil {
panic(err)
}
fmt.Println("從清單左側彈出元素:", val)
// 9 4 3 8 2 1
// LRange(ctx, key, start, stop) 擷取某個索引範圍裡的元素
vals, err := rdb.LRange(ctx, "test_list", 1, 4).Result()
if err != nil {
panic(err)
}
fmt.Println("擷取索引1到4的值:", vals)
// LTrim(ctx, key, start, stop) 對一個清單進行修剪,
// 隻讓清單保留指定區間内的元素,不在指定區間之内的元素都将被删除
val, err = rdb.LTrim(ctx, "test_list", 1, 4).Result() // 此時隻剩下1到4範圍内的值
if err != nil {
panic(err)
}
fmt.Println("val值:", val)
}
// 列印結果如下:
/*
test_list have existed
test_list delete success!
6
test_list的長度: 6
index是2的值: 4
插入成功
設定成功
[6 9 4 3 8 2 1] <nil>
從清單左側彈出元素: 6
擷取索引1到4的值: [4 3 8 2]
val值: OK
*/
3.操作redis Hash類型
Redis hash 是一個鍵值(key=>value)對集合。Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特别适合用于存儲對象。
下面是go-redis操作redis Hash類型的一些API:
- HSet:給key設定field和value
- HGet:擷取key某個field的value
- HMset:給key批量設定field和value
- HLen:擷取鍵值對個數
- HGetAll:擷取全部鍵值對元素
- HKeys:擷取所有的key
- HIncrBy:增加,成功傳回增加後的值
- HDel:删除鍵值對元素
- HExists:檢查key某個field是否存在
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// HSet 給key設定field和value
result, err := rdb.HSet(ctx, "user1", "name", "zhangsan").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1
// HMSet 批量設定
rdb.HMSet(ctx, "user1", map[string]interface{}{"age": 18, "sex": "male"})
// HGet 擷取某個field的value
name, err := rdb.HGet(ctx, "user1", "name").Result()
if err != nil {
panic(err)
}
fmt.Println(name) // zhangsan
// HMGet 批量擷取field的value
fields, err := rdb.HMGet(ctx, "user1", "name", "age").Result()
if err != nil {
panic(err)
}
fmt.Println(fields) // [zhangsan 18]
// HLen 擷取鍵值對個數
len, err := rdb.HLen(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(len) // 3
// HGetAll 擷取全部元素
all, err := rdb.HGetAll(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(all) // map[age:18 name:zhangsan sex:male]
// HKeys 擷取所有的key
keys, err := rdb.HKeys(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(keys) // [name age sex]
// HIncrBy 增加,成功傳回增加後的值
age, err := rdb.HIncrBy(ctx, "user1", "age", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(age) // 20
// HDel 删除鍵值對元素
result, err = rdb.HDel(ctx, "user1", "name").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1
// HExists 檢查某個元素是否存在
fmt.Println(rdb.HExists(ctx, "user1","name")) // hexists user1 name: false
}
// 列印結果如下:
/*
1
zhangsan
[zhangsan 18]
3
map[age:18 name:zhangsan sex:male]
[name age sex]
20
1
hexists user1 name: false
*/
4.操作redis Set類型
Redis 的 Set 是 string 類型的無序集合。
集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是 O(1)。
下面是go-redis操作redis Set集合類型的一些API:
- SAdd:向指定集合添加集合元素
- SSMembers:擷取集合中的所有成員
- SCard:擷取集合中成員的數量
- SIsMember:判斷某成員是否在集合中
- SRem:删除集合裡指定成員
- SPop:随機從集合中彈出一個元素
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// SAdd 向指定集合添加集合元素
result, err := rdb.SAdd(ctx, "dev_users", "zhangsan", "lisi", "wangwu", "zhangsan").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 3
// SMembers 擷取集合中的所有成員
members, err := rdb.SMembers(ctx, "dev_users").Result()
if err != nil {
panic(err)
}
fmt.Println(members) // [zhangsan wangwu lisi]
// SCard 擷取集合中成員的數量
count, err := rdb.SCard(ctx, "dev_users").Result()
if err != nil {
panic(err)
}
fmt.Println(count) // 3
// SIsMember 判斷某成員是否在集合中
is, err := rdb.SIsMember(ctx, "dev_users", "zhaoliu").Result()
if err != nil {
panic(err)
}
fmt.Println(is) // false
// SRem 删除集合裡指定成員
n, err := rdb.SRem(ctx, "dev_users", "zhangsan", "lisi").Result()
if err != nil {
panic(err)
}
fmt.Println(n) // 2
// SPop 随機從集合中彈出一個元素
user, err := rdb.SPop(ctx, "dev_users").Result() // 此時集合中隻剩wangwu,彈出wangwu了
if err != nil {
panic(err)
}
fmt.Println(user) // wangwu
}
// 列印結果如下:
/*
3
[zhangsan wangwu lisi]
3
false
2
wangwu
*/
下面是go-redis集合運算的一些API:
- SInter:求集合間的交集
- SDiff:求集合間的差集
- SUnion:求集合間的并集
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// 準備一些資料
// 先往dev_group1集合添加一些成員
result1, err := rdb.SAdd(ctx, "dev_group1", "zhangsan", "lisi", "wangwu", "zhangsan").Result()
if err != nil {
panic(err)
}
fmt.Println(result1) // 3
// 再往dev_group2集合添加一些成員
result2, err := rdb.SAdd(ctx, "dev_group2", "zhaoliu", "tiaiqi", "zhangsan", "lisi").Result()
if err != nil {
panic(err)
}
fmt.Println(result2) // 4
// SInter 求集合間的交集
inter, err := rdb.SInter(ctx, "dev_group1", "dev_group2").Result()
if err != nil {
panic(err)
}
fmt.Println("交集:", inter) // 交集: [zhangsan lisi]
// SDiff 求集合間的差集
diff, err := rdb.SDiff(ctx, "dev_group1", "dev_group2").Result() // dev_group1集合與dev_group2集合的差集
if err != nil {
panic(err)
}
fmt.Println("差集:", diff) // 差集: [wangwu]
diff2, err := rdb.SDiff(ctx, "dev_group2", "dev_group1").Result() // dev_group2集合與dev_group1集合的差集
if err != nil {
panic(err)
}
fmt.Println("差集:", diff2) // 差集: [zhaoliu tiaiqi]
// SUnion 求集合間的并集
union, err := rdb.SUnion(ctx, "dev_group1", "dev_group2").Result()
if err != nil {
panic(err)
}
fmt.Println("并集:", union) // 并集: [lisi wangwu zhaoliu tiaiqi zhangsan]
}
// 列印結果如下:
/*
3
4
交集: [zhangsan lisi]
差集: [wangwu]
差集: [zhaoliu tiaiqi]
并集: [lisi wangwu zhaoliu tiaiqi zhangsan]
*/
5.操作redis Zset類型
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。
下面是go-redis操作redis Zset有序集合類型的一些API:
- ZAdd:向一個有序集合中添加元素
- ZCard:擷取有序集合的元素個數
- ZCount:擷取有序集合指定區間内元素個數
- ZScore:擷取有序集合的元素的score
- ZRank:傳回有序集中指定成員的排名。其中有序內建員按分數值遞增(從小到大)順序排列。
- ZRevRank:傳回有序集合中指定成員的排名,有序內建員按分數值遞減(從大到小)排序
- ZRange:傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞增(從小到大)來排序。
- ZRevRange:傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞減(從大到小)來排列。
- ZIncrBy:對有序集合中指定成員的分數加上一個增量
- ZRangeByScore:通過分數傳回有序集合指定區間内的成員,分數從低到高排序
- ZRevRangeByScore:傳回有序集中指定分數區間内的成員,分數從高到低排序
- ZRemRangeByRank:移除有序集合中給定的排名區間的所有成員
- ZRemRangeByScore:移除有序集合中給定的分數區間的所有成員
- ZRem:移除有序集合中的一個或多個成員
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// ZAdd 向一個有序集合中添加元素
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 1,
Member: "python",
})
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 2,
Member: "c",
})
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 3,
Member: "java",
})
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 4,
Member: "c++",
})
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 5,
Member: "c#",
})
rdb.ZAdd(ctx, "test_zset", &redis.Z{
Score: 6,
Member: "visual bacis",
})
// ZCard 擷取有序集合的元素個數
count, err := rdb.ZCard(ctx, "test_zset").Result()
if err != nil {
panic(err)
}
fmt.Println(count) // 6
// ZCount 擷取有序集合指定區間内元素個數
// fmt.Println(rdb.ZCount(ctx, "test_zset", "2", "4"))
n, err := rdb.ZCount(ctx, "test_zset", "2", "4").Result()
if err != nil {
panic(err)
}
fmt.Println(n) // 3
// ZScore 擷取有序集合的元素的score
score, err := rdb.ZScore(ctx, "test_zset", "c++").Result()
if err != nil {
panic(err)
}
fmt.Println(score) // 4
// ZRank 傳回有序集中指定成員的排名。其中有序內建員按分數值遞增(從小到大)順序排列。
result, err := rdb.ZRank(ctx, "test_zset", "java").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 2
// ZRevRank 傳回有序集合中指定成員的排名,有序內建員按分數值遞減(從大到小)排序
result, err = rdb.ZRevRank(ctx, "test_zset", "java").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 3
// ZRange 傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞增(從小到大)來排序。
elems, err := rdb.ZRange(ctx, "test_zset", 0, 2).Result()
if err != nil {
panic(err)
}
fmt.Println(elems) // [python c java]
// ZRevRange 傳回有序集中,指定區間内的成員,其中成員的位置按分數值遞減(從大到小)來排列。
elems, err = rdb.ZRevRange(ctx, "test_zset", 0, 2).Result()
if err != nil {
panic(err)
}
fmt.Println(elems) // [visual bacis c# c++]
// ZIncrBy 對有序集合中指定成員的分數加上一個增量
r, err := rdb.ZIncrBy(ctx, "test_zset", 2, "c++").Result()
if err != nil {
panic(err)
}
fmt.Println(r) // 6
// ZRangeByScore 通過分數傳回有序集合指定區間内的成員,分數從低到高排序
res, err := rdb.ZRangeByScore(ctx, "test_zset", &redis.ZRangeBy{
Min: "2",
Max: "5",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res) // [c java c#]
// ZRevRangeByScore 傳回有序集中指定分數區間内的成員,分數從高到低排序
res, err = rdb.ZRevRangeByScore(ctx, "test_zset", &redis.ZRangeBy{
Min: "2",
Max: "5",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res) // [c# java c]
// ZRem 移除有序集合中的一個或多個成員
rem, err := rdb.ZRem(ctx, "test_zset", "visual bacis").Result()
if err != nil {
panic(err)
}
// 删除的元素個數
fmt.Println(rem) // 1
// ZRemRangeByRank 移除有序集合中給定的排名區間的所有成員
// 按照升序删除第一個和第二個元素
rem, err = rdb.ZRemRangeByRank(ctx, "test_zset", 0, 1).Result()
if err != nil {
panic(err)
}
fmt.Println(rem) // 2
// ZRemRangeByScore 移除有序集合中給定的分數區間的所有成員
// 删除score在2-4之間的元素
rem, err = rdb.ZRemRangeByScore(ctx, "test_zset", "2", "4").Result()
if err != nil {
panic(err)
}
fmt.Println(rem) // 1
}
// 列印結果如下:
/*
6
3
4
2
3
[python c java]
[visual bacis c# c++]
6
[c java c#]
[c# java c]
1
2
1
*/
6.管道操作
Redis管道可以在服務端未響應時,用戶端繼續向服務端發送請求,并最終一次性讀取所有服務端的響應。管道技術最顯著的優勢是提高了 redis 服務的性能。
下面是管道的操作示例:
package main
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
var incr *redis.IntCmd
_, err = rdb.Pipelined(ctx, func(piper redis.Pipeliner) error {
incr = piper.Incr(ctx, "pipelined_counter")
piper.Expire(ctx, "pipelined_counter", time.Hour)
return nil
})
if err != nil {
panic(err)
}
fmt.Println(incr.Val()) // 1
}
// 列印結果如下:
/*
1
*/
7.事務操作
事務可以了解為一個打包的批量執行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會導緻前面已做指令的復原,也不會造成後續的指令不做。
一個事務從開始到執行會經曆三個階段:開始事務、指令入隊及執行事務。
這裡是事務操作的示範:
待填。
8.釋出/訂閱
Redis釋出訂閱是一種消息通信模式:發送者 (pub) 發送消息,訂閱者 (sub) 接收消息。Redis的用戶端可訂閱任意數量的頻道。
Redis釋出的示範代碼:
// pub.go
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// 釋出
err := rdb.Publish(ctx, "mychannel1", "payload").Err()
if err != nil {
panic(err)
}
fmt.Println("publish done!")
}
Redis訂閱的示範代碼:
// sub.go
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}
// 訂閱頻道
pubsub := rdb.Subscribe(ctx, "mychannel1")
// 完成後關閉訂閱。
defer pubsub.Close()
// 接收消息
for {
msg, err := pubsub.ReceiveMessage(ctx)
if err != nil {
panic(err)
}
fmt.Println(msg.Channel, msg.Payload)
}
}
先啟動訂閱代碼sub.go,再啟動釋出代碼pub.go,即可看到效果。