Golang


文章目录



Golang_实战_连接redis_github

1 何为redis

Redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。

Redis 优势

性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。

丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

Redis与其他key-value存储有什么不同?

Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

2 连接redis

package main
import (
"fmt"
"/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()
}

2.1 读写

这里写入的值永远不会过期

package main

import (
"fmt"

"/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 = ("SET", "mykey", "superWang")
if err != nil {
fmt.Println("redis set failed:", err)
}

username, err := redis.String(("GET", "mykey"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Get mykey: %v \n", username)
}
}

如何设置过期呢,可以使用SET的附加参数

package main

import (
"fmt"
"time"

"/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 = ("SET", "mykey", "superWang", "EX", "5")
if err != nil {
fmt.Println("redis set failed:", err)
}

username, err := redis.String(("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(("GET", "mykey"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Get mykey: %v \n", username)
}
}

输出:
Get mykey: superWang
redis get failed: redigo: nil returned

2.2 检测值是否存在

EXISTS key

package main

import (
"fmt"

"/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 = ("SET", "mykey", "superWang")
if err != nil {
fmt.Println("redis set failed:", err)
}

is_key_exit, err := redis.Bool(("EXISTS", "mykey1"))
if err != nil {
fmt.Println("error:", err)
} else {
fmt.Printf("exists or not: %v \n", is_key_exit)
}

}

输出:
exists or not: false

2.3 删除

DEL key [key …]

package main

import (
"fmt"

"/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 = ("SET", "mykey", "superWang")
if err != nil {
fmt.Println("redis set failed:", err)
}

username, err := redis.String(("GET", "mykey"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Get mykey: %v \n", username)
}

_, err = ("DEL", "mykey")
if err != nil {
fmt.Println("redis delelte failed:", err)
}

username, err = redis.String(("GET", "mykey"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Get mykey: %v \n", username)
}
}

输出:
Get mykey: superWang
redis get failed: redigo: nil returned

2.4 读写json到redis

package main

import (
"encoding/json"
"fmt"

"/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 := ("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(("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"])
}

2.5 设置过期时间

EXPIRE key seconds

// 设置过期时间为24小时  
n, _ := ("EXPIRE", key, 24*3600)
if n == int64(1) {
fmt.Println("success")
}

2. 6 列表操作

代码:

package main

import (
"fmt"

"/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 = ("lpush", "runoobkey", "redis")
if err != nil {
fmt.Println("redis set failed:", err)
}

_, err = ("lpush", "runoobkey", "mongodb")
if err != nil {
fmt.Println("redis set failed:", err)
}
_, err = ("lpush", "runoobkey", "mysql")
if err != nil {
fmt.Println("redis set failed:", err)
}

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

for _, v := range values {
fmt.Println(string(v.([]byte)))
}
}

输出:
mysql
mongodb
redis

3 管道

请求/响应服务可以实现持续处理新请求,即使客户端没有准备好读取旧响应。这样客户端可以发送多个命令到服务器而无需等待响应,最后在一次读取多个响应。这就是管道化(pipelining),这个技术在多年就被广泛使用了。距离,很多POP3协议实现已经支持此特性,显著加速了从服务器下载新邮件的过程。
Redis很早就支持管道化,所以无论你使用任何版本,你都可以使用管道化技术

连接支持使用Send(),Flush(),Receive()方法支持管道化操作

Send(commandName string, args ...interface{}) error
Flush() error
Receive() (reply interface{}, err error)

Send向连接的输出缓冲中写入命令。Flush将连接的输出缓冲清空并写入服务器端。Recevie按照FIFO顺序依次读取服务器的响应。下例展示了一个简单的管道:

c.Send("SET", "foo", "bar")
c.Send("GET", "foo")
c.Flush()
c.Receive() // reply from SET
v, err = c.Receive() // reply from GET

Do方法组合了Send,Flush和 Receive方法。Do方法先写入命令,然后清空输出buffer,最后接收全部挂起响应包括Do方发出的命令的结果。如果任何响应中包含一个错误,Do返回错误。如果没有错误,Do方法返回最后一个响应。

应用

package main

import (
"fmt"

"/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)
}
}

输出:
PONG
key value
key2 does not exists