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