Golang操作Redis
安装第三方开源Redis库
注意 : 命令行操作不成功的直接去这个github网站里下载压缩包解压到指定目录即可
1. Set/Get 接口
package main
import (
"fmt"
"github.com/garyburd/redigo/redis" // 引入redis包
)
func main() {
//通过go向redis写入数据和读取数据
// 1. 链接到redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("redis.Dial err = ", err)
return
}
defer conn.Close() // 关闭
// 2、 通过go向redis写入数据 string [key - val]
_, err = conn.Do("Set", "name", "tomjerry 狗狗")
if err != nil {
fmt.Println("set err = ", err)
return
}
// 3.通过go向redis读取数据 string [key - val]
r, err := redis.String(conn.Do("Get", "name"))
if err != nil {
fmt.Println("set err = ", err)
return
}
// 返回的r的类型是interface{}
// 因为name对应的值是string,因此我们需要转换
// nameString := r.(string)
fmt.Println("操作 ok", r)
}
2. 操作Hash
说明:通过Golang对Redis操作 Hash数据类型
对hash数据结构,field-val 是一个一个放入和读取:
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
// 通过go向redis写入数据和 读取数据
// 1.链接到redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("redis.Dial err = ", err)
return
}
defer conn.Close()
// 2. 通过go向redis写入数据 string [key - val]
_, err = conn.Do("HSet", "user01", "name", "john")
if err != nil {
fmt.Println("hset err = ", err)
return
}
_, err := conn.Do("HSet", "user01", "age", 18)
if err != nil {
fmt.Println("hset err = ", err)
return
}
// 3.通过go向redis读取数据
r1, err :=redis.String(conn.Do("HGet", "user01", name))
if err != nil {
fmt.Println("hget err = ", err)
return
}
r2, err := redis.Do("HGet", "user01", "age")
if err != nil {
fmt.Println("hget err = ", err)
return
}
// 返回的r 是innterface{}
// 因为name对应的值是string,因此我们需要转换
// nameString := r.(string)
fmt.Printf("操作 OK r1 = %v r2 = %v\n", r1, r2)
}
对hash数据结构,field-val是 批量放入和读取:
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
conn, err := redis.Dial("tcp", "127.0.0.1:6397")
if err != nil {
fmt.Println("redis Dial err = ", err)
return
}
_, err := conn.Do("HMSet", "user02", "name", "jack", "age", 21)
if err != nil {
fmt.Println("HMSet err = ", err)
return
}
r, err := redis.String(conn.Do("HMGet", "user02", "name", "age"))
if err != nil {
fmt.Println("hmget err = ", err)
return
}
for i, V := range r {
fmt.Printf("r[%d] = %s\n", i, v)
}
}
3. 批量Set/Get数据
说明:通过golang对redis操作,一次操作可以Set/Get多个key-val数据
_, err := conn.Do("MSet", "name", "golang", "address", "北京")
r, err := redis.String(conn.Do("MGet", "name", "address"))
for _, v := range r {
fmt.Println(v)
}
3.1 给数据设置有效时间
说明:通过golang对redis操作,给 key-val设置有效时间
// 给name数据设置有效时间为10s
_, err = conn.Do("expire", "name", 10)
4. 操作List
说明: 通过golang对redis操作List数据类型
_, err := conn.Do("lpush", "heroList", "no1:悟空", 30, "no2:八戒", 33)
r, err := redis.String(conn.Do("rpop", "heroList"))
5. Redis 链接池
说明:通过Golang对Redis操作,还可以通过Redis链接池,步骤:
1)事先初始化一定数量的链接,放入到链接池
2)当Go需要操作Redis时,直接从Redis链接池取出链接即可
3)这样 可以节省临时获取Redis链接的时间,从而提高效率
4)示意图:
5 ) 链接池使用案例:
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
// 定义一个全局的pool
var pool *redis.Pool
//当线程启动时,就初始化链接池
func init() {
pool = &redis.Pool {
MaxIdle : 8, // 最大空闲连接数
MaxActive : 0, // 表示和数据库的最大链接数,0 表示没有限制
IdleTimeout : 100, // 最大空闲时间
Dial : func()(redis.Conn, error) {
// 初始化链接的代码,链接哪个ip的redis
return redis.Dial("tcp", "localhost:6379")
},
}
}
func main() {
// 先从pool取出一个链接
conn := pool.Get()
defer conn.Close()
_, err := conn.Do("Set", "name", "汤姆")
if err != nil {
fmt.Println("conn.Do err = ", err)
return
}
// 取出
r, err := redis.String(conn.Do("Get", "name"))
if err != nil {
fmt.Println("conn.Do err = ", err)
return
}
fmt.Println("r = ", r)
// 如果我们要从pool取出链接,一定保证链接池没有关闭
// pool.Close()
conn2 := pool.Get() // 取第二个链接
_, err = conn2.Do("Set","name2", "汤姆2")
if err != nil {
fmt.Println("conn.Do err = ", err)
return
}
// 取出
r2, err := redis.String(conn2.Do("Get", "name2"))
if err != nil {
fmt.Println("conn.Do err = ", err)
return
}
fmt.Println("r = ", r2)
// fmt.Println("conn2 = ", conn2)
}
注意:redis.Poll 结构介绍:
// github.com/garyburd/redigo/redis/pool.go
type Pool struct {
// Dial()方法返回一个连接,从在需要创建连接到的时候调用
Dial func() (Conn, error)
// TestOnBorrow()方法是一个可选项,该方法用来诊断一个连接的健康状态
TestOnBorrow func(c Conn, t time.Time) error
// 最大空闲连接数
MaxIdle int
// 一个pool所能分配的最大的连接数目
// 当设置成0的时候,该pool连接数没有限制
MaxActive int
// 空闲连接超时时间,超过超时时间的空闲连接会被关闭。
// 如果设置成0,空闲连接将不会被关闭
// 应该设置一个比redis服务端超时时间更短的时间
IdleTimeout time.Duration
// 如果Wait被设置成true,则Get()方法将会阻塞
Wait bool
// mu protects fields defined below.
mu sync.Mutex
cond *sync.Cond
closed bool
active int
// 空闲连接队列
idle list.List
}
主要参数:
MaxIdle
- 表示连接池空闲连接列表的长度限制
- 空闲列表是一个栈式的结构,先进后出
MaxActive
- 表示连接池中最大连接数限制
- 主要考虑到服务端支持的连接数上限,以及应用之间”瓜分”连接数
IdleTimeout
- 空闲连接的超时设置,一旦超时,将会从空闲列表中摘除
- 该超时时间时间应该小于服务端的连接超时设置
区分两种使用场景:
-
高频调用的场景,需要尽量压榨redis的性能:
- 调高MaxIdle的大小,该数目小于maxActive,由于作为一个缓冲区一样的存在,扩大缓冲区自然没有问题
- 调高MaxActive,考虑到服务端的支持上限,尽量调高
- IdleTimeout由于是高频使用场景,设置短一点也无所谓,需要注意的一点是MaxIdle设置的长了,队列中的过期连接可能会增多,这个时候IdleTimeout也要相应变化
-
低频调用的场景,调用量远未达到redis的负载,稳定性为重:
- MaxIdle可以设置的小一些
- IdleTimeout相应地设置小一些
时间时间应该小于服务端的连接超时设置
区分两种使用场景:
-
高频调用的场景,需要尽量压榨redis的性能:
- 调高MaxIdle的大小,该数目小于maxActive,由于作为一个缓冲区一样的存在,扩大缓冲区自然没有问题
- 调高MaxActive,考虑到服务端的支持上限,尽量调高
- IdleTimeout由于是高频使用场景,设置短一点也无所谓,需要注意的一点是MaxIdle设置的长了,队列中的过期连接可能会增多,这个时候IdleTimeout也要相应变化
-
低频调用的场景,调用量远未达到redis的负载,稳定性为重:
- MaxIdle可以设置的小一些
- IdleTimeout相应地设置小一些
- MaxActive随意,够用就好,容易检测到异常