使用redigo库操作redis
安装
go get github.com/gomodule/redigo/redis
连接
c, err := redis.Dial("tcp",
"172.17.84.205:6379",
redis.DialKeepAlive(1*time.Second),
redis.DialPassword("123456"),
redis.DialConnectTimeout(5*time.Second),
redis.DialReadTimeout(1*time.Second),
redis.DialWriteTimeout(1*time.Second))
if err != nil {
fmt.Println("error:", err)
return
}
defer c.Close()
set/get key-value
_, err = c.Do("set", "testkey1", "Hello from redis")
r, err := redis.String(c.Do("get", "testkey1"))
如果要设置过期时间
_, err = c.Do("set", "testkey1", "Hello from redis", "EX", "5")
其中"EX", "5"是设置的过期时间5秒
mset/mget 设置获取多个键值
_, err = c.Do("mset", "name", "Michael", "sex", "M", "age", 23, "postcode", 2343253)
stringValues, err := redis.Strings(c.Do("mget", "name", "sex"))
intValues, err := redis.Ints(c.Do("mget", "age", "postcode"))
for _, v := range stringValues {
fmt.Println(v)
}
for _, i := range intValues {
fmt.Println(i)
}
HSET key field value
将哈希表 key 中的域 field 的值设为 value
_, err = c.Do("hset", "books", "name", "golang", "author", "Moon", "pages", "4000")
if err != nil {
fmt.Println("err:", err)
}
v, err := redis.String(c.Do("hget", "books", "name"))
v, err := redis.String(c.Do("hget", "books", "author"))
HMSET/HGETALL,HMGET
在使用前先说明几个函数
- type Args []interface{}
从结构化的值构造命令参数
- func (args Args) Add(value ...interface{}) Args
添加值到Args
- func (args Args) AddFlat(v interface{}) Args
添加Map, Slice, struct等的值到Args
- func ScanStruct(src []interface{}, dest interface{}) error
将name和value从src转变成dest
示例代码如下
package main
import (
"fmt"
"os"
"time"
redis "github.com/gomodule/redigo/redis"
)
type Book struct {
BookName string
Author string
PageCount string
Press string
}
func main() {
c, err := redis.Dial("tcp",
"172.17.84.205:6379",
redis.DialKeepAlive(1*time.Second),
redis.DialPassword("123456"),
redis.DialConnectTimeout(5*time.Second),
redis.DialReadTimeout(1*time.Second),
redis.DialWriteTimeout(1*time.Second))
errCheck(err)
defer c.Close()
//Struct
top1 := Book{
BookName: "Crazy golang",
Author: "Moon",
PageCount: "600",
Press: "GoodBook",
}
if _, err = c.Do("HMSET", redis.Args{}.Add("Top1").AddFlat(&top1)...); err != nil {
fmt.Println(err)
return
}
//Map
top2 := map[string]string{
"BookName": "Mast C++",
"Author": "Diablo",
"PageCount": "2000",
"Press": "BLZ",
}
if _, err = c.Do("HMSET", redis.Args{}.Add("Top2").AddFlat(top2)...); err != nil {
fmt.Println(err)
return
}
top3 := []string{"BookName", "Deep learning",
"Author", "Barl",
"PageCount", "2600",
"Publish House", "BLZ"}
_, err = c.Do("HMSET", redis.Args{}.Add("Top3").AddFlat(top3)...)
errCheck(err)
topx := Book{}
for _, item := range []string{"Top1", "Top2", "Top3"} {
value, err := redis.Values(c.Do("HGETALL", item))
errCheck(err)
err = redis.ScanStruct(value, &topx)
errCheck(err)
fmt.Printf("%s[%+v]\n", item, topx)
}
stringsValue, err := redis.Strings(c.Do("HMGET", "Top1", "BookName", "Author"))
errCheck(err)
fmt.Printf("hmget:%+v\n", stringsValue)
}
func errCheck(err error) {
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
redis连接池
使用连接池的目的就是复用之前建立的连接,不用每次都重建TCP连接,提高吞吐率。
有几个参数说明一下
MaxIdle: pool中最大Idle连接数量
MaxActive: pool中最大分配的连接数量,设为0无限制
IdleTimeout: idle的时间,超过idle时间连接关闭。设为0 idle的连接不close
Wait: 设为true,当请求时如果达到MaxActive会等待有连接被close。设为false,当请求时如果达到MaxActive会返回error
package main
import (
"fmt"
"os"
"sync"
"time"
redis "github.com/gomodule/redigo/redis"
)
const (
MAXIDLE = 50
MAXACTIVE = 5000
IDLETIMEOUT = 30 * time.Second
ROUNTINECOUNT = 50
)
func deferClose(con *redis.Conn) {
fmt.Println("close")
(*con).Close()
}
func main() {
redisPool := &redis.Pool{
MaxIdle: MAXIDLE,
MaxActive: MAXACTIVE,
IdleTimeout: IDLETIMEOUT,
Wait: true,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp",
"172.17.84.205:6379",
redis.DialKeepAlive(20*time.Second),
redis.DialPassword("123456"),
redis.DialConnectTimeout(15*time.Second),
redis.DialReadTimeout(15*time.Second),
redis.DialWriteTimeout(15*time.Second))
if err != nil {
fmt.Println(err)
}
return c, err
},
}
var wg sync.WaitGroup
wg.Add(2 * ROUNTINECOUNT)
for i := 0; i < ROUNTINECOUNT; i++ {
go func(routineNum int) {
for cnt := 0; cnt < 1000; cnt++ {
c := redisPool.Get()
//defer c.Close()
key := fmt.Sprintf("key_%d_%d", routineNum, cnt)
value := fmt.Sprintf("value_%d_%d", routineNum, cnt)
_, err := c.Do("set", key, value)
if err != nil {
fmt.Printf("set %s:%v\n", key, err)
}
fmt.Printf("s %s\n", value)
if cnt%50 == 0 {
aCount := redisPool.Stats().ActiveCount
wCount := redisPool.Stats().WaitCount
fmt.Printf("activeCount:%d, waitCount:%d\n", aCount, wCount)
}
c.Close()
//time.Sleep(50 * time.Millisecond)
}
wg.Done()
}(i)
go func(routineNum int) {
for cnt := 0; cnt < 1000; cnt++ {
c := redisPool.Get()
//defer c.Close()
key := fmt.Sprintf("key_%d_%d", routineNum, cnt)
value, err := redis.String(c.Do("get", key))
if err != nil {
fmt.Printf("get %s:%v\n", key, err)
}
fmt.Printf("g %s\n", value)
c.Close()
}
wg.Done()
}(i)
}
wg.Wait()
}
func errCheck(err error) {
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
在测试时发现
c := redisPool.Get()
defer c.Close()
Close()始终没有被执行,所以当达到MaxActive时就被卡住,不执行了。
所以在使用完直接调用c.Close()
原因没去仔细查,如果有谁知道原因了,请告诉我一声
详细代码: