/**
redis_util Redis工具包
作者:hongbo
日期:2020-4-22
*/
package redis_util
import (
"encoding/json"
"errors"
"log"
"runtime"
"strings"
"time"
redigo "github.com/garyburd/redigo/redis"
)
// RedisPool redis 多服务端连接池,1个应用同时连接多个redis服务
var RedisPool map[string]*redigo.Pool
// 初始化redis 多端连接池
// @param addrs enterprise=192.168.3.14:1379,service=192.168.3.14:2379,other=192.168.3.14:3379
func InitRedis(addrs string) {
InitRedisBySize(addrs, 300, 30, 240)
}
// 初始化redis连接池,支持多个redis库
func InitRedisBySize(addrs string, maxSize, maxIdle, timeout int) {
RedisPool = map[string]*redigo.Pool{}
addr := strings.Split(addrs, ",")
for _, v := range addr {
saddr := strings.Split(v, "=")
RedisPool[saddr[0]] = &redigo.Pool{MaxActive: maxSize, MaxIdle: maxIdle,
IdleTimeout: time.Duration(timeout) * time.Second, Dial: func() (redigo.Conn, error) {
return redigo.Dial("tcp", saddr[1])
}}
}
}
// 分流redis ,并存入字符串缓存
func PutKV(key string, obj interface{}) bool {
return Put("other", key, obj, -1)
}
// 存储KV对,并设置永不超时
func PutCKV(code, key string, obj interface{}) bool {
return Put(code, key, obj, -1)
}
// 存储KV对,可设置超时时间,单位秒
func Put(code, key string, obj interface{}, timeout int) bool {
b := false
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
var err error
_obj, _err := json.Marshal(obj)
if _err != nil {
log.Println("redisutil-SET-序列化出错Error", _err)
return b
}
if timeout < 1 {
_, err = conn.Do("SET", key, _obj)
} else {
_, err = conn.Do("SET", key, _obj, "EX", timeout)
}
if nil != err {
log.Println("redisutil-SETError-put", err)
} else {
b = true
}
return b
}
// 批量存储KV对,可指定超时时间,obj格式=[[key,value],,,]
func BulkPut(code string, timeout int, obj ...interface{}) bool {
b := false
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
var err error
for _, _tmp := range obj {
tmp, ok := _tmp.([]interface{})
if ok && len(tmp) == 2 {
key, kok := tmp[0].(string)
if kok && key != "" {
_obj, _err := json.Marshal(tmp[1])
if _err != nil {
log.Println("redisutil-SET-序列化出错Error", _err)
return b
}
if timeout < 1 {
_, err = conn.Do("SET", key, _obj)
} else {
_, err = conn.Do("SET", key, _obj, "EX", timeout)
}
}
}
}
if nil != err {
b = false
log.Println("redisutil-SETError-put", err)
} else {
b = b && true
}
return b
}
// 存储KV对,Value是字节数组,可指定超时时间
func PutBytes(code, key string, data *[]byte, timeout int) (err error) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
if timeout < 1 {
_, err = conn.Do("SET", key, *data)
} else {
_, err = conn.Do("SET", key, *data, "EX", timeout)
}
if nil != err {
log.Println("redisutil-SETError", err)
}
return
}
// 设置超时时间,单位秒
func SetExpire(code, key string, expire int) error {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
_, err := conn.Do("expire", key, expire)
return err
}
// 判断一个key是否存在
func Exists(code, key string) (bool, error) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
repl, err := conn.Do("exists", key)
ret, _ := redigo.Int(repl, err)
return ret == 1, err
}
// 依据Key,获取Value 自动转化为字符串格式
func GetStr(code, key string) string {
res := Get(code, key)
str, _ := res.(string)
return str
}
// 依据Key,获取Value 自动转化为int格式
func GetInt(code, key string) int {
result, _ := GetNewInt(code, key)
return result
}
// 依据Key,获取Value 兼容int类型数据将自动转换
func GetNewInt(code, key string) (int, error) {
var res interface{}
err := GetNewInterface(code, key, &res)
var result int
if str, ok := res.(float64); ok {
result = int(str)
}
return result, err
}
// 依据Key,获取字符串,返回interface{},需要自己断言
func Get(code, key string) (result interface{}) {
GetInterface(code, key, &result)
return
}
// NOTE: 建议使用GetNewInterface
// 依据Key,获取字符串,返回interface{} 为兼容老代码所写
func GetInterface(code, key string, result interface{}) {
GetNewInterface(code, key, result)
}
// NOTE:注意result必须为指针对象
// 依据Key,获取字符串,返回interface{} ,基础方法,部分外部接口依赖此方法
func GetNewInterface(code, key string, result interface{}) error {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("GET", key)
if nil != err {
log.Println("redisutil-GetError", err)
} else {
var ok bool
var res []byte
if res, ok = ret.([]byte); ok {
err = json.Unmarshal(res, result)
if err != nil {
log.Println("Get ERROR:", err.Error())
}
}
}
return err
}
// 依据Key,获取字节数组
func GetBytes(code, key string) (ret *[]byte, err error) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
var r interface{}
r, err = conn.Do("GET", key)
if err != nil {
log.Println("redisutil-GetBytesError", err)
} else {
if tmp, ok := r.([]byte); ok {
ret = &tmp
} else {
err = errors.New("redis返回数据格式不对")
}
}
return
}
// FIXME: 写注释,表示很忧伤,GetNewBytes/GetBytes的实现,没看出来差异啊
// 依据Key,获取字节数组
func GetNewBytes(code, key string) (ret *[]byte, err error) {
defer catch()
redisPool := RedisPool[code]
if redisPool == nil {
err = errors.New("redis code " + code + " is nil")
log.Println("redisutil-GetNewBytesError", err)
return
}
conn := redisPool.Get()
defer conn.Close()
var r interface{}
r, err = conn.Do("GET", key)
if err != nil {
log.Println("redisutil-GetNewBytesError", err)
} else if r != nil {
if tmp, ok := r.([]byte); ok {
ret = &tmp
}
}
return
}
// 删所有key,清理Redis库
func FlushDB(code string) bool {
b := false
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
var err error
_, err = conn.Do("FLUSHDB")
if nil != err {
log.Println("redisutil-FLUSHDBError", err)
} else {
b = true
}
return b
}
// 批量删除多个key
// NOTE: key 为变参
func Del(code string, key ...interface{}) bool {
defer catch()
b := false
conn := RedisPool[code].Get()
defer conn.Close()
var err error
_, err = conn.Do("DEL", key...)
if nil != err {
log.Println("redisutil-DELError", err)
} else {
b = true
}
return b
}
// 根据key前辍,批量删除
// NOTE: key前缀 如:key*
func DelByCodePattern(code, key string) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("KEYS", key)
var result []interface{}
if nil != err {
log.Println("redisutil-GetError", err)
} else {
result = ret.([]interface{})
for k := 0; k < len(result); k++ {
conn.Do("DEL", string(result[k].([]uint8)))
}
}
}
// 指定key,自增计数,并返回增加后的值
func Incr(code, key string) int64 {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("INCR", key)
if nil != err {
log.Println("redisutil-INCR-Error", err)
} else {
if res, ok := ret.(int64); ok {
return res
} else {
return 0
}
}
return 0
}
// 指定key,自减计数,并返回增加后的值
func Decrby(code, key string, val int) int64 {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("DECRBY", key, val)
if nil != err {
log.Println("redisutil-DECR-Error", err)
} else {
if res, ok := ret.(int64); ok {
return res
} else {
return 0
}
}
return 0
}
// 根据正则key,获取结果
func GetKeysByPattern(code, key string) []interface{} {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("KEYS", key)
if nil != err {
log.Println("redisutil-GetKeysError", err)
return nil
} else {
res, _ := ret.([]interface{})
return res
}
}
// 批量取多个key的值
func Mget(code string, key []string) []interface{} {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
interfaceKeys := make([]interface{}, len(key))
for n, k := range key {
interfaceKeys[n] = k
}
ret, err := conn.Do("MGET", interfaceKeys...)
if nil != err {
log.Println("redisutil-MgetError", err)
return nil
} else {
res, _ := ret.([]interface{})
return res
}
}
// 常规KV,出栈操作,查询指定Key,返回Value后,删除此KV对
func Pop(code string, key string) (result interface{}) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("GET", key)
if nil != err {
log.Println("redisutil-PopError", err)
} else {
var ok bool
var res []byte
if res, ok = ret.([]byte); ok {
err = json.Unmarshal(res, &result)
if err != nil {
log.Println("Poperr", err)
}
}
conn.Do("DEL", key)
}
return
}
// List数据 KV,队首出栈操作,对应RPOP队尾出栈
func LPOP(code, list string) (result interface{}) {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("LPOP", list)
if nil != err {
log.Println("redisutil-LPopError", err)
} else {
if res, ok := ret.([]byte); ok {
err = json.Unmarshal(res, &result)
log.Println(err)
}
}
return
}
// List数据 后端入栈,在List末尾追加数据 对应LPUSH在队首插入数据
func RPUSH(code, list string, val interface{}) bool {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
_obj, _ := json.Marshal(val)
_, err := conn.Do("RPUSH", list, _obj)
if nil != err {
log.Println("redisutil-RPUSHError", err)
return false
}
return true
}
// List数据长度
func LLEN(code, list string) int64 {
defer catch()
conn := RedisPool[code].Get()
defer conn.Close()
ret, err := conn.Do("LLEN", list)
if nil != err {
log.Println("redisutil-LLENError", err)
return 0
}
if res, ok := ret.(int64); ok {
return res
} else {
return 0
}
}
func catch() {
if r := recover(); r != nil {
log.Println(r)
for skip := 0; ; skip++ {
_, file, line, ok := runtime.Caller(skip)
if !ok {
break
}
go log.Printf("%v,%v\n", file, line)
}
}
}