重學Go語言之如何使用Redis
Redis
是我們開發(fā)應用程序中很常用的NoSQL
數(shù)據(jù)庫,作為一款內(nèi)存數(shù)據(jù)庫,Redis
也支持數(shù)據(jù)持久化(RDB
與AOF
兩種機制),所以Redis
既可以作為數(shù)據(jù)庫來使用,也可以作為關系型數(shù)據(jù)庫與應用程序之間的緩存來使用。
那么在Go語言中要如何連接和操作Redis
呢?在這篇文章中,我們一起來探究一下!
開始
在開始操作Redis
之前,我們先來初始化我們的示例項目,接著再安裝連接Redis
所需要的第三方庫。
初始化項目
由于我們接下來要用到的第三方庫需要Go Moudles
的支持,因此我們先使用go mod init
命令初始化我們的示例項目:
go?mod?init?GoTest
Go Redis
由于Go語言的標準庫并沒有提供對Redis
的支持,因此就需要使用到Go
社區(qū)的第三方庫。
在這里推薦用Go Reids
,該庫最新版本的Github
地址為:
github.com/redis/go-redis
為什么推薦使用Go Redis
推薦使用Go Redis
的原因有以下幾點:
Go Redis
是Redis
官方推薦的第三方庫。- 社區(qū)中使用的人也比較多,而且文檔很齊全。
- 支持不同種類的
Redis
客戶端,比如哨兵客戶端,集群客戶端等。 - 支持所有的
Redis
版本。
Go Redis安裝
通過cd
命令進入項目,執(zhí)行go get
命令就可以下載安裝 github.com/redis/go-redis/v9
:
cd?GoTest #最新版本為v9 go?get?github.com/redis/go-redis/v9
連接Redis
如同所有的Client/Server
應用程序一樣,要想操作Redis
,就必須先與Redis
建立網(wǎng)絡連接。
簡單連接
如果是連接部署在內(nèi)部網(wǎng)絡沒有密碼的Redis
服務器,只需要IP
與端口號(port)
就可以連接了:
import?"github.com/redis/go-redis/v9" opt?:=?&redis.Options{ ?Addr:???"localhost:6379", } rdb?:=?redis.NewClient(opt)
上面代碼中,可以概述為以下兩個步驟:
- 實例化一個
redis.Options
表示連接配置對象,該對象當前設置了Addr
字段,該 字段表示Redis
服務器的地址。 - 將
redis.Options
對象傳給redis.NewClient()
函數(shù),redis.NewClient()
函數(shù)會返回一個操作Redis
的句柄rdb
。
redis.ParseURL
除了自定義redis.Options
,另一種方式是調(diào)用redis.ParseURL()
函數(shù)以下格式的URL
,該函數(shù)會返回一個redis.Options
對象:
redis://<user>:<pass>@localhost:6379/<port>
因此我們可以將上面連接Redis
的例子改寫為:
import?"github.com/redis/go-redis/v9" opt,?err?:=?redis.ParseURL("redis://localhost:6379") if?err?!=?nil?{ ?panic(err) } rdb?:=?redis.NewClient(opt)
redis.Options
前面我們連接Redis
的例子中只用到了redis.Options
的Addr
字段:
opt?:=?&redis.Options{ ?Addr:???"localhost:6379", }
除此之外,我們也可以通過redis.Options
的字段配置連接的參數(shù):
opt?:=?&redis.Options{ ??//地址與端口 ?Addr:???"localhost:6379", ?//數(shù)據(jù)庫,0~16 ??DB:0, ??//用戶名,在Redis6.0以上使用 ?Username:"test", ?//密碼 ?Password:"123456", ?//命令最大重試次數(shù) ??MaxRetries:3, ??//連接超時 ?DialTimeout:3, ??//連接池 ?PoolSize:30, ?//最小空閑連接數(shù) ??MinIdleConns:10, ??//最大空閑連接數(shù) ?MaxIdleConns:30, }
上面列舉的是redis.Options
比較常用的字段,實際上還有很多其他的字段參數(shù),這里就不一一列舉了。
Redis操作
雖然已經(jīng)通過redis.NewClient()
函數(shù)獲取操作Redis
的句柄了,但要操作Redis
了,還需要創(chuàng)建一個Context
對象,這是因為所有的Go Redis
操作Redis
的方法的第一個參數(shù)都是Context
。
創(chuàng)建Context
Context
表示上下文,可以用于超時控制、數(shù)據(jù)傳遞以及性能監(jiān)控等。
通過context
包的Backgroud()
函數(shù)可以創(chuàng)建一個根Context
:
ctx?:=?context.Background()
執(zhí)行已支持的命令
Go Redis
為所有的Redis
命令都提供了對應的方法,比如SET
命令對應的方法為Set
,HGET
對應的方法為HGet
。
因此如果想執(zhí)行對應的Redis
命令,直接調(diào)用對應的方法即可,比如:
redis>?set?test?test_value?0 redis>?hset?user:1?id?1?name?小張?gender?男
使用Go Redis
執(zhí)行上面命令的代碼為:
rdb.Set(ctx,?"test",?"test_value",?0) rdb.HSet(ctx,?"user:1",?"id",1,"name",?"小張",?"gender",?"男")
Redis
命令執(zhí)行后,一般都有返回值,但是不同的命令的返回值是不一樣的,最簡單的返回如SET
命令返回一個字符串,HSET
命令會返回一個整數(shù),而HGETALL
會返回一個類似結(jié)構(gòu)體的數(shù)據(jù):
package?main import?( ?"context" ?"fmt" ?"github.com/redis/go-redis/v9" ) func?main()?{ ?rdb?:=?redis.NewClient(&redis.Options{ ??Addr:?"localhost:6379", ?}) ?ctx?:=?context.Background() ?setCmd?:=?rdb.Set(ctx,?"test",?"test_value",?0) ?hSetCmd?:=?rdb.HSet(ctx,?"user:1",?"id",?1,?"name",?"小張",?"gender",?"男") ?hAllGetCmd?:=?rdb.HGetAll(ctx,?"user:1") }
在上面的代碼中,我們可以看到在執(zhí)行不同命令時,會返回不同cmd
對象,比如Set()
方法返回一個StatusCmd
對象,HSet()
方法返回IntCmd
對象,而HGetAll()
方法返回MapStringStringCmd
對象。
有了cmd
對象后,就可以獲取命令執(zhí)行結(jié)果及錯誤信息,有兩種方法,一種是直接調(diào)用Result()
方法返回結(jié)果與錯誤信息:
fmt.Println(setCmd.Result()) fmt.Println(hSetCmd.Result()) fmt.Println(hAllGetCmd.Result())
另一種方法是分開獲得取結(jié)果和錯誤信息:
fmt.Println(setCmd.Val(),setCmd.Err()) fmt.Println(hSetCmd.Val(),hSetCmd.Err()) fmt.Println(hAllGetCmd.Val(),hAllGetCmd.Err())
上面兩種輸出方式輸出的的結(jié)果都是:
OK <nil>
3 <nil>
map[gender:男 id:1 name:小張] <nil>
如果我們獲得取一個不存在的key,此時命令會返回一個特殊的錯誤redis.Nil
,這是一個特殊的錯誤,用于表示是否獲得取了空值:
val,?err?:=?rdb.Get(ctx,?"key").Result() switch?{ case?err?==?redis.Nil: ?fmt.Println("key不存在") case?err?!=?nil: ?fmt.Println("錯誤",?err) case?val?==?"": ?fmt.Println("值是空字符串") }
執(zhí)行尚未支持的命令
當然,有時候Redis
新的版本可能會添加一些新的命令,而Go Redis
還未提供支持,這時候可以調(diào)用Do
方法來執(zhí)行對應的命令,實際上Do()
方法可以用于執(zhí)行任何命令:
val,?err?:=?rdb.Do(ctx,?"hgetall",?"user:1").Result() if?err?!=?nil?{ ?if?err?==?redis.Nil?{ ??fmt.Println("key?does?not?exists") ??return ?} ?panic(err) } fmt.Println(val.(MapStringStringCmd))
從上面的例子可以看出Do()
執(zhí)行不同的命令后返回值也是不同的。
結(jié)果集映射
有時候我們查詢Redis后會返回多個key-value
的結(jié)果集,比如mget
、hget
,hgetall
這樣的命令,Go redis
提供了Scan()
方法可以將查詢回來的結(jié)果集掃描進對應的結(jié)構(gòu)體當中:
package?main import?( ?"context" ?"fmt" ?"github.com/redis/go-redis/v9" ) type?User?struct?{ ?ID?????int????`redis:"id"` ?Name???string?`redis:"name"` ?Gender?string?`redis:"gender"` } func?main()?{ ?rdb?:=?redis.NewClient(&redis.Options{ ??Addr:?"localhost:6379", ?}) ?ctx?:=?context.Background() ?var?u?User ?err?:=?rdb.HGetAll(ctx,?"user:1").Scan(&u) ?if?err?!=?nil?{ ??panic(err) ?} ?fmt.Println(u) }
管道
管道(pipeline)
允許在一次請求中發(fā)送多條Redis
命令,并返回多個結(jié)果,這樣可以節(jié)省一個一個執(zhí)行命令需要付出的往返回時間:
package?main import?( ?"context" ?"fmt" ?"github.com/redis/go-redis/v9" ) func?main()?{ ?opt?:=?&redis.Options{ ??Addr:?"localhost:6379", ?} ?rdb?:=?redis.NewClient(opt) ?ctx?:=?context.Background() ?cmds,?err?:=?rdb.Pipelined(ctx,?func(pipe?redis.Pipeliner)?error?{ ??pipe.Set(ctx,?"test",?"test_value",?0) ??pipe.HSet(ctx,?"user:1",?"id",?1,?"name",?"小張",?"gender",?"男") ??pipe.HGetAll(ctx,?"user:1") ??return?nil ?}) ?if?err?!=?nil?{ ??panic(err) ?} ?for?_,?cmd?:=?range?cmds?{ ??switch?c?:=?cmd.(type)?{ ??case?*redis.IntCmd: ???fmt.Println(c.Val()) ??case?*redis.StatusCmd: ???fmt.Println(c.Val()) ??case?*redis.MapStringStringCmd: ???fmt.Println(c.Val()) ??} ?} }
發(fā)布與訂閱
Go Redis
支持發(fā)布與訂閱(Pub/Sub
)。
發(fā)布消息
發(fā)布消息的方法為Publish
:
package?main import?( ?"context" ?"fmt" ?"github.com/redis/go-redis/v9" ) func?main()?{ ?rdb?:=?redis.NewClient(&redis.Options{ ??Addr:?"localhost:6379", ?}) ?ctx?:=?context.Background() ??//向渠道發(fā)送消息 ?err?:=?rdb.Publish(ctx,?"mychannel",?"this?is?a?message").Err() ????if?err?!=?nil?{ ????????panic(err) ????} }
訂閱消息
訂閱消息的方法為Subscribe
,訂閱之后通過返回的句柄調(diào)用ReceiveMessage()
方法接收消息:
package?main import?( ?"context" ?"fmt" ?"github.com/redis/go-redis/v9" ) func?main()?{ ?rdb?:=?redis.NewClient(&redis.Options{ ??Addr:?"localhost:6379", ?}) ?ctx?:=?context.Background() ?pubsub?:=?rdb.Subscribe(ctx,?"mychannel") ?defer?pubsub.Close() ??//接收消息 ?for?{ ??msg,?err?:=?pubsub.ReceiveMessage(ctx) ??if?err?!=?nil?{ ???panic(err) ??} ??fmt.Printf("從%s渠道接受到%s",?msg.Channel,?msg.Payload) ?} }
小結(jié)
在本文中,我們講解用github.com/redis/go-redis
連接和操作Redis的基本操作,其實這個庫支持很多高級的功能,比如哨兵,集群、分片等功能,以后在別的文章再講解吧。
以上就是重學Go語言之如何使用Redis的詳細內(nèi)容,更多關于Go Redis的資料請關注腳本之家其它相關文章!
相關文章
Go用兩個協(xié)程交替打印100以內(nèi)的奇偶數(shù)的方法詳解
這篇文章主要給大家詳細介紹了Go用兩個協(xié)程交替打印100以內(nèi)的奇偶數(shù)的示例代碼,文中給大家介紹了兩個實現(xiàn)方法,使用無緩沖的channel和設置GOMAXPROCS=1,介紹的非常詳細,需要的朋友可以參考下2023-08-08Go語言中基本數(shù)據(jù)類型的相互轉(zhuǎn)換詳解
Go在不同類型的變量之間賦值時需要顯示轉(zhuǎn)換,不能自動轉(zhuǎn)換。這篇文章主要和大家介紹了Go語言中基本數(shù)據(jù)類型的相互轉(zhuǎn)換,感興趣的小伙伴可以了解一下2022-10-10Go語言學習之將mp4通過rtmp推送流媒體服務的實現(xiàn)方法
對音視頻一直是小白,決定沉下心來,好好研究一下音視頻知識,下面這篇文章主要給大家介紹了關于Go語言學習之將mp4通過rtmp推送流媒體服務的實現(xiàn)方法,需要的朋友可以參考下2022-12-12