123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /**
- redis_util Redis工具包<br/>
- 作者:hongbo<br/>
- 日期:2020-4-22<br/>
- */
- 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 多端连接池 <br/>
- // @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)
- }
- }
- }
|