Reids
Redis是一個(gè)開(kāi)源的、使用C語(yǔ)言編寫的、支持網(wǎng)絡(luò)交互的、可基于內(nèi)存也可持久化的Key-Value數(shù)據(jù)庫(kù)。
Reids的特點(diǎn)
- 速度快,因?yàn)閿?shù)據(jù)存在內(nèi)存中,類似于HashMap,HashMap的優(yōu)勢(shì)就是查找和操作的時(shí)間復(fù)雜度都是O(1)
- 支持豐富數(shù)據(jù)類型,支持string,list,set,sorted set,hash
- 支持事務(wù),操作都是原子性,所謂的原子性就是對(duì)數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行
- 豐富的特性:可用于緩存,消息,按key設(shè)置過(guò)期時(shí)間,過(guò)期后將會(huì)自動(dòng)刪除
- 可以對(duì)數(shù)據(jù)進(jìn)行持久化和數(shù)據(jù)同步
- Redis是單進(jìn)程單線程的
golang操作Redis
redigo是GO語(yǔ)言的一個(gè)redis客戶端實(shí)現(xiàn)。項(xiàng)目位于地址
安裝
go get github.com/garyburd/redigo/redis
redigo的使用
連接
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
cnn, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("Connect to redis error", err)
return
}else {
fmt.Println("連接成功")
}
defer cnn.Close()
}
命令
數(shù)據(jù)類型轉(zhuǎn)換
go對(duì)應(yīng)redis的數(shù)據(jù)類型
| Go Type | Conversion |
|---|---|
| []byte | Sent as is |
| string | Sent as is |
| int, int64 | strconv.FormatInt(v) |
| float64 | strconv.FormatFloat(v, 'g', -1, 64) |
| bool | true -> "1", false -> "0" |
| nil | "" |
| all other types | fmt.Print(v) |
Redis 命令響應(yīng)會(huì)用以下Go類型表示:
| Redis type | Go type |
|---|---|
| error | redis.Error |
| integer | int64 |
| simple string | string |
| bulk string | []byte or nil if value not present. |
| array | []interface{} or nil if value not present. |
可以使用GO的類型斷言或者reply輔助函數(shù)將返回的interface{}轉(zhuǎn)換為對(duì)應(yīng)類型
Do方法組合了Send,Flush和 Receive方法。Do方法先寫入命令,然后清空輸出buffer,最后接收全部掛起響應(yīng)包括Do方發(fā)出的命令的結(jié)果。如果任何響應(yīng)中包含一個(gè)錯(cuò)誤,Do返回錯(cuò)誤。如果沒(méi)有錯(cuò)誤,Do方法返回最后一個(gè)響應(yīng)。
- 讀寫
寫入值永不過(guò)期
_, err = c.Do("SET", "username", "nick")
if err != nil {
fmt.Println("redis set failed:", err)
}
寫入值10S后過(guò)期
_, err = c.Do("SET", "password", "123456", "EX", "10")
if err != nil {
fmt.Println("redis set failed:", err)
}
簡(jiǎn)單讀
username, err := redis.String(c.Do("GET", "username"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Got username %v \n", username)
}
- 批量讀寫
批量讀寫
key:=make([]string,5)
value:=make([]string,5)
for i:=0;i<5 ;i++ {
key=append(key,string(i) )
value=append(value,string(i) )
}
_, err = cnn.Do("MSET", key,value)
if err != nil {
fmt.Println("redis set failed:", err)
}
val,err:= cnn.Do("MGET",key)
if err != nil {
fmt.Println("redis set failed:", err)
}
批量寫入讀取對(duì)象(Hashtable)
HMSET key field value [field value ...]
HMGET key field [field ...]
檢測(cè)key值是否存在
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)
}
刪除key
_, err = c.Do("DEL", "mykey")
if err != nil {
fmt.Println("redis delelte failed:", err)
}
設(shè)置過(guò)期時(shí)間
n, _ := rs.Do("EXPIRE", key, 24*3600)
if n == int64(1) {
fmt.Println("success")
}
管道
請(qǐng)求/響應(yīng)服務(wù)可以實(shí)現(xiàn)持續(xù)處理新請(qǐng)求,即使客戶端沒(méi)有準(zhǔn)備好讀取舊響應(yīng)。這樣客戶端可以發(fā)送多個(gè)命令到服務(wù)器而無(wú)需等待響應(yīng),最后在一次讀取多個(gè)響應(yīng)。這就是管道化(pipelining),這個(gè)技術(shù)在多年就被廣泛使用了。
c.Send("SET", "foo", "bar")//Send向連接的輸出緩沖中寫入命令
c.Send("GET", "foo")//
c.Flush()//Flush將連接的輸出緩沖清空并寫入服務(wù)器端
//Recevie按照FIFO順序依次讀取服務(wù)器的響應(yīng)
c.Receive() // reply from SET
v, err = c.Receive() // reply from GET
Do方法組合了Send,Flush和 Receive方法。Do方法先寫入命令,然后清空輸出buffer,最后接收全部掛起響應(yīng)包括Do方發(fā)出的命令的結(jié)果。如果任何響應(yīng)中包含一個(gè)錯(cuò)誤,Do返回錯(cuò)誤。如果沒(méi)有錯(cuò)誤,Do方法返回最后一個(gè)響應(yīng)。
并發(fā)
連接并不支持并發(fā)調(diào)用寫入方法(Send,Flush)或者讀取方法(Receive)。但是連接支持并發(fā)的讀寫。
因?yàn)镈o方法組合了Send,F(xiàn)lush和Receive,Do不可以與其他方法并發(fā)執(zhí)行
連接池
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
"runtime"
"sync"
"time"
)
var w sync.WaitGroup
func newRdsPool(server, auth string) *redis.Pool {
return &redis.Pool{
//最大空閑
MaxIdle: 100,
//最大活動(dòng)量
MaxActive: 30,
//空閑超時(shí)
IdleTimeout: 60 * time.Second,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", server)
if err != nil {
return nil, err
}
if auth == "" {
return c, err
}
if _, err := c.Do("AUTH", auth); err != nil {
c.Close()
return nil, err
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
}
func main() {
w.Add(2)
runtime.GOMAXPROCS(runtime.NumCPU())
var rc1 redis.Conn = newRdsPool(`127.0.0.1:6379`, ``).Get()
defer rc1.Close()
}