Go實戰(zhàn)--golang中使用redis

生命不止落午,繼續(xù) go go go !!!

以前介紹過golang中如何使用sqlite3:

《Go實戰(zhàn)–go語言操作sqlite數(shù)據(jù)庫(The way to go)》

今天跟大家分享的是如何在golang中使用redis數(shù)據(jù)庫槽棍。

##何為redis

官網(wǎng):

https://redis.io/

Redis is an in-memory database open-source software project implementing a networked, in-memory key-value store with optional durability.

Redis是一個開源的、使用C語言編寫的、支持網(wǎng)絡(luò)交互的捂寿、可基于內(nèi)存也可持久化的Key-Value數(shù)據(jù)庫酌畜。

Redis 優(yōu)勢

性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。

豐富的數(shù)據(jù)類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作谣旁。

原子 – Redis的所有操作都是原子性的床佳,同時Redis還支持對幾個操作全并后的原子性執(zhí)行。

豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性榄审。

Redis與其他key-value存儲有什么不同砌们?

Redis有著更為復雜的數(shù)據(jù)結(jié)構(gòu)并且提供對他們的原子性操作,這是一個不同于其他數(shù)據(jù)庫的進化路徑搁进。Redis的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結(jié)構(gòu)的同時對程序員透明浪感,無需進行額外的抽象。

Redis運行在內(nèi)存中但是可以持久化到磁盤饼问,所以在對不同數(shù)據(jù)集進行高速讀寫時需要權(quán)衡內(nèi)存影兽,因為數(shù)據(jù)量不能大于硬件內(nèi)存。在內(nèi)存數(shù)據(jù)庫方面的另一個優(yōu)點是莱革,相比在磁盤上相同的復雜的數(shù)據(jù)結(jié)構(gòu)峻堰,在內(nèi)存中操作起來非常簡單讹开,這樣Redis可以做很多內(nèi)部復雜性很強的事情。同時捐名,在磁盤格式方面他們是緊湊的以追加的方式產(chǎn)生的旦万,因為他們并不需要進行隨機訪問。

##windows安裝redis

這里只簡單介紹一下Windows上redis的安裝:

在官網(wǎng)中可以看到這樣的描述:

Windows

The Redis project does not officially support Windows. However, the Microsoft Open Tech group develops and maintains this Windows port targeting Win64

下載

直接去github上下載就好了:

https://github.com/MicrosoftArchive/redis/releases

這里可以下載msi文件和zip文件镶蹋,兩者區(qū)別就是msi文件是安裝文件成艘,安裝的過程中會幫助我們配好環(huán)境變量,所以推薦梅忌。

這里需要提示一下安裝過程中狰腌,如果修改了端口號,一定要記啄恋:

圖1

啟動服務(wù)端

安裝成功后琼腔,通過終端鍵入如下命令:

redis-server.exe redis.windows.conf

1

一切沒問題會出現(xiàn)下面的提示:

[11368] 13 Jul 10:10:31.487 # Creating Server TCP listening socket 127.0.0.1:6379: bind: No error

啟動客戶端

新打開一個終端,啟動redis客戶端踱葛,鍵入命令:

redis-cli.exe -h 127.0.0.1 -p 6379

1

測試:

127.0.0.1:6379> set mykey abc

OK

127.0.0.1:6379> get mykey

"abc"

1

2

3

4

##開源庫redigo的使用

github地址:

https://github.com/garyburd/redigo

文檔地址:

http://godoc.org/github.com/garyburd/redigo/redis

獲鹊ち:

go get github.com/garyburd/redigo/redis

1

連接redis

package main

import (

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

讀寫

這里寫入的值永遠不會過期

package main

import (

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

_, err = c.Do("SET", "mykey", "superWang")

if err != nil {

fmt.Println("redis set failed:", err)

}

username, err := redis.String(c.Do("GET", "mykey"))

if err != nil {

fmt.Println("redis get failed:", err)

} else {

fmt.Printf("Get mykey: %v \n", username)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

如何設(shè)置過期呢,可以使用SET的附加參數(shù):

package main

import (

"fmt"

"time"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

_, err = c.Do("SET", "mykey", "superWang", "EX", "5")

if err != nil {

fmt.Println("redis set failed:", err)

}

username, err := redis.String(c.Do("GET", "mykey"))

if err != nil {

fmt.Println("redis get failed:", err)

} else {

fmt.Printf("Get mykey: %v \n", username)

}

time.Sleep(8 * time.Second)

username, err = redis.String(c.Do("GET", "mykey"))

if err != nil {

fmt.Println("redis get failed:", err)

} else {

fmt.Printf("Get mykey: %v \n", username)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

輸出:

Get mykey: superWang

redis get failed: redigo: nil returned

批量寫入讀取

MGET key [key …]

MSET key value [key value …]

批量寫入讀取對象(Hashtable)

HMSET key field value [field value …]

HMGET key field [field …]

檢測值是否存在

EXISTS key

package main

import (

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

_, err = c.Do("SET", "mykey", "superWang")

if err != nil {

fmt.Println("redis set failed:", err)

}

is_key_exit, err := redis.Bool(c.Do("EXISTS", "mykey1"))

if err != nil {

fmt.Println("error:", err)

} else {

fmt.Printf("exists or not: %v \n", is_key_exit)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

輸出:

exists or not: false

刪除

DEL key [key …]

package main

import (

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

_, err = c.Do("SET", "mykey", "superWang")

if err != nil {

fmt.Println("redis set failed:", err)

}

username, err := redis.String(c.Do("GET", "mykey"))

if err != nil {

fmt.Println("redis get failed:", err)

} else {

fmt.Printf("Get mykey: %v \n", username)

}

_, err = c.Do("DEL", "mykey")

if err != nil {

fmt.Println("redis delelte failed:", err)

}

username, err = redis.String(c.Do("GET", "mykey"))

if err != nil {

fmt.Println("redis get failed:", err)

} else {

fmt.Printf("Get mykey: %v \n", username)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

輸出:

Get mykey: superWang

redis get failed: redigo: nil returned

讀寫json到redis

package main

import (

"encoding/json"

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

key := "profile"

imap := map[string]string{"username": "666", "phonenumber": "888"}

value, _ := json.Marshal(imap)

n, err := c.Do("SETNX", key, value)

if err != nil {

fmt.Println(err)

}

if n == int64(1) {

fmt.Println("success")

}

var imapGet map[string]string

valueGet, err := redis.Bytes(c.Do("GET", key))

if err != nil {

fmt.Println(err)

}

errShal := json.Unmarshal(valueGet, &imapGet)

if errShal != nil {

fmt.Println(err)

}

fmt.Println(imapGet["username"])

fmt.Println(imapGet["phonenumber"])

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

設(shè)置過期時間

EXPIRE key seconds

// 設(shè)置過期時間為24小時?

n, _ := rs.Do("EXPIRE", key, 24*3600)?

if n == int64(1) {?

? ? fmt.Println("success")?

}?

1

2

3

4

5

列表操作

命令:

redis 127.0.0.1:6379> LPUSH runoobkey redis

(integer) 1

redis 127.0.0.1:6379> LPUSH runoobkey mongodb

(integer) 2

redis 127.0.0.1:6379> LPUSH runoobkey mysql

(integer) 3

redis 127.0.0.1:6379> LRANGE runoobkey 0 10

1) "mysql"

2) "mongodb"

3) "redis"

1

2

3

4

5

6

7

8

9

10

11

代碼實現(xiàn):

package main

import (

"fmt"

"github.com/garyburd/redigo/redis"

)

func main() {

c, err := redis.Dial("tcp", "127.0.0.1:6379")

if err != nil {

fmt.Println("Connect to redis error", err)

return

}

defer c.Close()

_, err = c.Do("lpush", "runoobkey", "redis")

if err != nil {

fmt.Println("redis set failed:", err)

}

_, err = c.Do("lpush", "runoobkey", "mongodb")

if err != nil {

fmt.Println("redis set failed:", err)

}

_, err = c.Do("lpush", "runoobkey", "mysql")

if err != nil {

fmt.Println("redis set failed:", err)

}

values, _ := redis.Values(c.Do("lrange", "runoobkey", "0", "100"))

for _, v := range values {

fmt.Println(string(v.([]byte)))

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

輸出:

mysql

mongodb

redis

管道

請求/響應(yīng)服務(wù)可以實現(xiàn)持續(xù)處理新請求尸诽,即使客戶端沒有準備好讀取舊響應(yīng)甥材。這樣客戶端可以發(fā)送多個命令到服務(wù)器而無需等待響應(yīng),最后在一次讀取多個響應(yīng)性含。這就是管道化(pipelining)洲赵,這個技術(shù)在多年就被廣泛使用了。距離商蕴,很多POP3協(xié)議實現(xiàn)已經(jīng)支持此特性叠萍,顯著加速了從服務(wù)器下載新郵件的過程。

Redis很早就支持管道化绪商,所以無論你使用任何版本苛谷,你都可以使用管道化技術(shù)

連接支持使用Send(),F(xiàn)lush()格郁,Receive()方法支持管道化操作

Send(commandName string, args ...interface{}) error

Flush() error

Receive() (reply interface{}, err error)

1

2

3

Send向連接的輸出緩沖中寫入命令腹殿。Flush將連接的輸出緩沖清空并寫入服務(wù)器端。Recevie按照FIFO順序依次讀取服務(wù)器的響應(yīng)例书。下例展示了一個簡單的管道:

c.Send("SET", "foo", "bar")

c.Send("GET", "foo")

c.Flush()

c.Receive() // reply from SET

v, err = c.Receive() // reply from GET

1

2

3

4

5

Do方法組合了Send,Flush和 Receive方法锣尉。Do方法先寫入命令,然后清空輸出buffer雾叭,最后接收全部掛起響應(yīng)包括Do方發(fā)出的命令的結(jié)果悟耘。如果任何響應(yīng)中包含一個錯誤,Do返回錯誤织狐。如果沒有錯誤暂幼,Do方法返回最后一個響應(yīng)。

##開源庫go-redis/redis的使用

github地址:

https://github.com/go-redis/redis

文檔地址:

https://godoc.org/github.com/go-redis/redis

獲纫破取:

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

1

應(yīng)用:

package main

import (

"fmt"

"github.com/go-redis/redis"

)

func main() {

client := redis.NewClient(&redis.Options{

Addr:? ? "127.0.0.1:6379",

Password: "", // no password set

DB:? ? ? 0,? // use default DB

})

pong, err := client.Ping().Result()

fmt.Println(pong, err)

err = client.Set("key", "value", 0).Err()

if err != nil {

panic(err)

}

val, err := client.Get("key").Result()

if err != nil {

panic(err)

}

fmt.Println("key", val)

val2, err := client.Get("key2").Result()

if err == redis.Nil {

fmt.Println("key2 does not exists")

} else if err != nil {

panic(err)

} else {

fmt.Println("key2", val2)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

輸出:

PONG

key value

key2 does not exists

————————————————

版權(quán)聲明:本文為CSDN博主「一蓑煙雨1989」的原創(chuàng)文章旺嬉,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明厨埋。

原文鏈接:https://blog.csdn.net/wangshubo1989/article/details/75050024

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邪媳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荡陷,更是在濱河造成了極大的恐慌雨效,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件废赞,死亡現(xiàn)場離奇詭異徽龟,居然都是意外死亡,警方通過查閱死者的電腦和手機唉地,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門据悔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耘沼,你說我怎么就攤上這事极颓。” “怎么了群嗤?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵菠隆,是天一觀的道長。 經(jīng)常有香客問我狂秘,道長骇径,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任赃绊,我火速辦了婚禮既峡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碧查。我一直安慰自己运敢,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布忠售。 她就那樣靜靜地躺著传惠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稻扬。 梳的紋絲不亂的頭發(fā)上卦方,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音泰佳,去河邊找鬼盼砍。 笑死尘吗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的浇坐。 我是一名探鬼主播睬捶,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼近刘!你這毒婦竟也來了擒贸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤觉渴,失蹤者是張志新(化名)和其女友劉穎介劫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體案淋,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡座韵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哎迄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片回右。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漱挚,靈堂內(nèi)的尸體忽然破棺而出翔烁,到底是詐尸還是另有隱情,我是刑警寧澤旨涝,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布蹬屹,位于F島的核電站,受9級特大地震影響白华,放射性物質(zhì)發(fā)生泄漏慨默。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一弧腥、第九天 我趴在偏房一處隱蔽的房頂上張望厦取。 院中可真熱鬧,春花似錦管搪、人聲如沸虾攻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霎箍。三九已至,卻和暖如春澡为,著一層夾襖步出監(jiān)牢的瞬間漂坏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留顶别,地道東北人谷徙。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像筋夏,于是被迫代替她去往敵國和親蒂胞。 傳聞我的和親對象是個殘疾皇子图呢,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容