package redis import ( "context" "encoding/json" "errors" "fmt" "net/url" "reflect" "strconv" "time" "91porn-server/common/log" goredis "github.com/go-redis/redis" ) //命令参考问题 http://redisdoc.com/persistence/index.html // Handler 缓存操作句柄 var Handler *Client // Options 配置项 type Options struct { Addr string `json:"addr"` // 地址 Pwd string `json:"pwd"` // 密码 MaxRetries int `json:"maxRetries"` // 重试次数 DB int `json:"db"` //数据库 PoolSize int `json:"poolSize"` //链接池数量 MinIdleConns int `json:"minIdleConns"` //最小空闲连接数 } // Client Redis客户端 type Client struct { client *goredis.Client } // Script 是可复用的 Redis Lua 脚本。RunScript 会优先执行 EVALSHA, // Redis 尚未缓存脚本时由 go-redis 自动回退到 EVAL。 type Script struct { script *goredis.Script } // NewScript 预计算脚本 SHA,调用方应复用返回值而不是每次请求重新创建。 func NewScript(source string) *Script { return &Script{script: goredis.NewScript(source)} } // Hash 返回脚本 SHA1,主要用于诊断和测试。 func (s *Script) Hash() string { if s == nil || s.script == nil { return "" } return s.script.Hash() } type Member = goredis.Z // Message 消息体 type Message struct { Channel string `json:"channel"` Payload string `json:"payload"` } // WithOptions 启动redis客户端连接 func WithOptions(options Options) (*Client, error) { client := goredis.NewClient(&goredis.Options{ Addr: options.Addr, Password: options.Pwd, MaxRetries: options.MaxRetries, DB: options.DB, MinIdleConns: options.MinIdleConns, PoolSize: options.PoolSize, }) if err := client.Ping().Err(); err != nil { log.Error("can't ping redis addr", log.Any("addr", options.Addr), log.Any("db", options.DB), log.E(err)) return nil, err } log.Info("redis connections success", log.Any("addr", options.Addr), log.Any("db", options.DB), log.Any("poolSize", options.PoolSize), log.Any("minIdleConns", options.MinIdleConns)) Handler = &Client{client: client} return Handler, nil } func WithURL(rawurl string) (*Client, error) { u, err := url.Parse(rawurl) if err != nil { return nil, err } auth := u.User host := u.Host path := u.Path rdb := 0 query := u.Query() if len(path) > 1 { path = path[1:] rdb, err = strconv.Atoi(path) if err != nil { log.Error("redis WithURL wrong db", log.Any("db", path)) return nil, err } } pwd, _ := auth.Password() smr := query.Get("maxRetries") maxRetries := 0 if len(smr) > 0 { maxRetries, err = strconv.Atoi(smr) if err != nil { log.Error("redis WithURL wrong maxRetries", log.Any("maxRetries", smr)) return nil, err } } poolSize := 70 poolSizeStr := query.Get("poolSize") if poolSizeStr != "" { poolSize, err = strconv.Atoi(poolSizeStr) if err != nil { poolSize = 50 } } minIdleConns := 50 minIdleConnsStr := query.Get("minIdleConns") if minIdleConnsStr != "" { minIdleConns, err = strconv.Atoi(minIdleConnsStr) if err != nil { minIdleConns = 30 } } opt := Options{ Addr: host, Pwd: pwd, MaxRetries: maxRetries, DB: rdb, PoolSize: poolSize, MinIdleConns: minIdleConns, } return WithOptions(opt) } // Close 关闭redis func (r *Client) Close() error { if r.client == nil { return nil } if err := r.client.Close(); err != nil { log.Error("close redis-connection failed") return err } log.Info("close redis-connection successfully") return nil } // SetBit 位操作 func (r *Client) SetBit(key string, offset int64, value int) error { if key == "" { return errors.New("key should not empty") } return r.client.SetBit(key, offset, value).Err() } // GetBit 获取位值 func (r *Client) GetBit(key string, offset int64) (int, error) { if key == "" { return 0, errors.New("key should not empty") } data, err := r.client.GetBit(key, offset).Result() if err != nil { return 0, err } return int(data), nil } // Set 设置键值对 func (r *Client) Set(key string, value interface{}, expirTime time.Duration) error { if key == "" { return errors.New("key should not empty") } return r.client.Set(key, value, expirTime).Err() } // Get 根据键 获取值 func (r *Client) Get(key string) (*string, error) { if key == "" { return nil, errors.New("key should not empty") } data, err := r.client.Get(key).Result() if err != nil { if err == goredis.Nil { return nil, nil } return nil, err } return &data, nil } func (r *Client) GetString(key string) (string, error) { if key == "" { return "", errors.New("key should not empty") } value, err := r.client.Get(key).Result() if err != nil && err != goredis.Nil { return "", err } return value, nil } // Get 根据键 获取值 func (r *Client) GetObj(bind interface{}, key string) error { if key == "" { return errors.New("key should not empty") } data, err := r.client.Get(key).Bytes() if err != nil { if err == goredis.Nil { return nil } return err } return json.Unmarshal(data, &bind) } // Get 根据键 获取值 func (r *Client) Scan(key string, val interface{}) error { if key == "" { return errors.New("key should not empty") } return r.client.Get(key).Scan(val) } // ScanKeys 异步迭代匹配key,不阻塞存取线程 func (r *Client) ScanKeys(match string) (keys []string, err error) { if match == "" { return nil, errors.New("match key should not empty") } var cursor uint64 var tmpKey []string tmpKey, cursor, err = r.client.Scan(cursor, match, 100).Result() if err != nil { return } keys = append(keys, tmpKey...) for cursor > 0 { tmpKey, cursor, err = r.client.Scan(cursor, match, 100).Result() if err != nil { return } keys = append(keys, tmpKey...) } return } // Get 是否存在某一个建 func (r *Client) IsExist(key string) bool { if key == "" { return false } data, err := r.client.Exists(key).Result() if err != nil { return false } return data != 0 } // Del 删除键值 func (r *Client) Del(keys ...string) (n int64, err error) { return r.DelContext(context.Background(), keys...) } // DelContext 删除键值并继承调用方取消和超时。 func (r *Client) DelContext(ctx context.Context, keys ...string) (n int64, err error) { if ctx == nil { return 0, errors.New("redis DelContext context must not be nil") } if r == nil || r.client == nil { return 0, errors.New("redis DelContext client must not be nil") } return r.client.WithContext(ctx).Del(keys...).Result() } // Subscribe constructs a field func (r *Client) Subscribe(channel ...string) (sub *goredis.PubSub, err error) { pubsub := r.client.Subscribe(channel...) if err := pubsub.Ping("ack:ok"); err != nil { log.Error(fmt.Sprintf("pubsub ping failed %+v:", err)) return nil, err } if _, err = pubsub.Receive(); err != nil { log.Error(fmt.Sprintf("pubsub receive failed %+v:", err)) return nil, err } log.Info("pubsub successfully") return pubsub, nil } // Publish 创建订阅频道 发布消息 func (r *Client) Publish(channel string, message interface{}) error { flag, err := r.client.Publish(channel, message).Result() if err != nil { log.Error(fmt.Sprintf("publish failed %+v:", err)) return err } log.Info(fmt.Sprintf("publish successfully flag:%d", flag)) return nil } // Lpop 按顺序弹出元素 从队列头部弹出 func (r *Client) Lpop(key string) (string, error) { result, err := r.client.LPop(key).Result() if err != nil { log.Error(fmt.Sprintf("LPop failed %+v:", err)) return "", err } return result, nil } // RPop 从线程安全队列取尾部取出元素 func (r *Client) RPop(key string) (string, error) { result, err := r.client.RPop(key).Result() if err != nil { log.Error(fmt.Sprintf("RPop failed %+v:", err)) return "", err } return result, nil } // Lpush push 添加元素到头部 func (r *Client) Lpush(key string, values ...interface{}) error { if err := r.client.LPush(key, values...).Err(); err != nil { log.Error(fmt.Sprintf("LPush failed %+v:", err)) return err } return nil } // RPush push 添加元素到尾部 func (r *Client) RPush(key string, values ...interface{}) error { if err := r.client.RPush(key, values...).Err(); err != nil { log.Error(fmt.Sprintf("RPush failed %+v:", err)) return err } return nil } // RPushPipeline 将 values 按 batchSize 拆成多个 RPUSH,并通过一个 Pipeline 顺序执行。 // 返回最后一个 RPUSH 执行后的列表长度。调用方应限制单次 values 的数量,避免生成过大的 Pipeline。 func (r *Client) RPushPipeline(key string, values []string, batchSize int) (int64, error) { return r.RPushPipelineContext(context.Background(), key, values, batchSize) } // RPushPipelineContext 与 RPushPipeline 相同,并继承调用方取消和超时。 func (r *Client) RPushPipelineContext( ctx context.Context, key string, values []string, batchSize int, expirations ...time.Duration, ) (int64, error) { if ctx == nil { return 0, errors.New("redis RPushPipelineContext context must not be nil") } if batchSize <= 0 { return 0, fmt.Errorf("redis RPushPipeline batchSize must be positive") } if len(values) == 0 { return 0, nil } if len(expirations) > 1 { return 0, errors.New("redis RPushPipelineContext accepts at most one expiration") } var expiration time.Duration if len(expirations) == 1 { expiration = expirations[0] if expiration <= 0 { return 0, errors.New("redis RPushPipelineContext expiration must be positive") } } if r == nil || r.client == nil { return 0, errors.New("redis RPushPipelineContext client must not be nil") } var lastCmd *goredis.IntCmd var expireCmd *goredis.BoolCmd _, err := r.client.WithContext(ctx).Pipelined(func(pipe goredis.Pipeliner) error { for start := 0; start < len(values); start += batchSize { end := start + batchSize if end > len(values) { end = len(values) } args := make([]interface{}, end-start) for i := start; i < end; i++ { args[i-start] = values[i] } lastCmd = pipe.RPush(key, args...) } if expiration > 0 { // 与 RPUSH 位于同一连接、同一 Pipeline。即使响应丢失后清理 // 与迟到命令交错,重新创建的 building key 也不会永久残留。 expireCmd = pipe.Expire(key, expiration) } return nil }) if err != nil { log.Error("RPushPipeline failed", log.E(err)) return 0, err } length, err := lastCmd.Result() if err != nil { log.Error("RPushPipeline result failed", log.E(err)) return 0, err } if expireCmd != nil { expired, expireErr := expireCmd.Result() if expireErr != nil { log.Error("RPushPipeline expire result failed", log.E(expireErr)) return 0, expireErr } if !expired { return 0, errors.New("redis RPushPipeline failed to expire list") } } return length, nil } // RPopLPush 线程安全队列 func (r *Client) RPopLPush(key string, value string) (string, error) { result, err := r.client.RPopLPush(key, value).Result() if err != nil { log.Error(fmt.Sprintf("RPopLPush failed %+v:", err)) return "", err } return result, nil } // BRPopLPush 阻塞线程安全队列 func (r *Client) BRPopLPush(key string, value string, timeout time.Duration) (string, error) { result, err := r.client.BRPopLPush(key, value, timeout).Result() if err != nil { log.Error(fmt.Sprintf("BRPopLPush failed %+v:", err)) return "", err } return result, nil } // LRem 从列表中删除元素 func (r *Client) LRem(key string, count int64, value string) (int64, error) { result, err := r.client.LRem(key, count, value).Result() if err != nil { log.Error(fmt.Sprintf("BRPopLPush failed %+v:", err)) return 0, err } return result, nil } // MGet 批量获取Get值 func (r *Client) MGet(keys ...string) ([]interface{}, error) { if len(keys) == 0 { return nil, nil } result, err := r.client.MGet(keys...).Result() if err != nil { log.Error(fmt.Sprintf("MGet failed %+v:", err)) return nil, err } return result, nil } // MSet 批量设置Set值 func (r *Client) MSet(pairs ...interface{}) error { if _, err := r.client.MSet(pairs...).Result(); err != nil { log.Error(fmt.Sprintf("MSet failed %+v:", err)) return err } return nil } // LRange 获取列表值 func (r *Client) LRange(key string, start int64, stop int64) ([]string, error) { data, err := r.client.LRange(key, start, stop).Result() if err != nil { log.Error(fmt.Sprintf("MSet failed %+v:", err)) return nil, err } return data, nil } // LCount 获取列表的数量 func (r *Client) LCount(key string) (int64, error) { cnt, err := r.client.LLen(key).Result() if err != nil { log.Error(fmt.Sprintf("MSet failed %+v:", err)) return 0, err } return cnt, nil } // LTrim 保留指定范围内的元素 func (r *Client) Ltrim(key string, start, end int64) (string, error) { result, err := r.client.LTrim(key, start, end).Result() if err != nil { log.Error(fmt.Sprintf("MSet failed %+v:", err)) return "", err } return result, nil } // AppendByte 追加bytes func (r *Client) AppendByte(key string, data []byte) (int64, error) { str := string(data) result, err := r.client.Append(key, str).Result() if err != nil { log.Error(fmt.Sprintf("MSet failed %+v:", err)) return 0, err } return result, nil } // ExpireKey 对键设置过期时间 func (r *Client) ExpireKey(key string, expirTime time.Duration) (bool, error) { result, err := r.client.Expire(key, expirTime).Result() if err != nil { log.Error(fmt.Sprintf("ExpireKey failed %+v:", err)) return false, err } return result, nil } // ExpireKey 对键设置指定过期时间 func (r *Client) ExpireKeAt(key string, expirTime time.Time) (bool, error) { result, err := r.client.ExpireAt(key, expirTime).Result() if err != nil { log.Error(fmt.Sprintf("ExpireKeAt failed %+v:", err)) return false, err } return result, nil } // Do 批处理执行redis func (r *Client) Do(arg ...interface{}) (interface{}, error) { result, err := r.client.Do(arg).Result() if err != nil { log.Error(fmt.Sprintf("Do failed %+v:", err)) return nil, err } return result, nil } // Eval 执行Lua脚本。涉及多个Redis键的读写必须通过脚本保证原子性。 func (r *Client) Eval(script string, keys []string, args ...interface{}) (interface{}, error) { return r.EvalContext(context.Background(), script, keys, args...) } // EvalContext 执行Lua脚本并继承调用方取消和超时。 func (r *Client) EvalContext( ctx context.Context, script string, keys []string, args ...interface{}, ) (interface{}, error) { if ctx == nil { return nil, errors.New("redis EvalContext context must not be nil") } if r == nil || r.client == nil { return nil, errors.New("redis EvalContext client must not be nil") } result, err := r.client.WithContext(ctx).Eval(script, keys, args...).Result() if err != nil { log.Error("Eval failed", log.E(err)) return nil, err } return result, nil } // RunScript 执行预编译脚本,优先使用 EVALSHA 并在 NOSCRIPT 时自动回退 EVAL。 func (r *Client) RunScript(script *Script, keys []string, args ...interface{}) (interface{}, error) { return r.RunScriptContext(context.Background(), script, keys, args...) } // RunScriptContext 与 RunScript 相同,并将取消和超时传递到 Redis 命令。 func (r *Client) RunScriptContext( ctx context.Context, script *Script, keys []string, args ...interface{}, ) (interface{}, error) { if ctx == nil { return nil, errors.New("redis RunScriptContext context must not be nil") } if script == nil || script.script == nil { return nil, errors.New("redis RunScriptContext script must not be nil") } if r == nil || r.client == nil { return nil, errors.New("redis RunScriptContext client must not be nil") } result, err := script.script.Run(r.client.WithContext(ctx), keys, args...).Result() if err != nil { log.Error("RunScript failed", log.E(err)) return nil, err } return result, nil } // redis 管道流 func (r *Client) Piplined(fn func(goredis.Pipeliner) error) ([]goredis.Cmder, error) { return r.client.Pipelined(fn) } // 生成管道流对象 func (r *Client) Pipliner() goredis.Pipeliner { return r.client.Pipeline() } // setNx 锁 func (r *Client) SetNX(key string, value interface{}, expiration time.Duration) (bool, error) { return r.SetNXContext(context.Background(), key, value, expiration) } // SetNXContext 原子写入键并继承调用方取消和超时。 func (r *Client) SetNXContext( ctx context.Context, key string, value interface{}, expiration time.Duration, ) (bool, error) { if ctx == nil { return false, errors.New("redis SetNXContext context must not be nil") } if r == nil || r.client == nil { return false, errors.New("redis SetNXContext client must not be nil") } result, err := r.client.WithContext(ctx).SetNX(key, value, expiration).Result() if err != nil { log.Error(fmt.Sprintf("SetNX failed %+v:", err)) return false, err } return result, nil } // Setnx 设置键值对 正确的封装 func (r *Client) Setnx_NewOK(key string, value interface{}, expirTime time.Duration) (v bool, err error) { return r.SetNX(key, value, expirTime) } // 有序集合操作 添加多个有序集合 func (r *Client) ZAdd(key string, z ...Member) (int64, error) { count, err := r.client.ZAdd(key, z...).Result() if err != nil { log.Error(fmt.Sprintf("ZAdd failed %+v:", err)) return 0, err } return count, nil } // 有序集合操作 指定成员增加传入值 func (r *Client) ZIncrBy(key string, inc float64, m string) (float64, error) { count, err := r.client.ZIncrBy(key, inc, m).Result() if err != nil { log.Error(fmt.Sprintf("ZIncrBy failed %+v:", err)) return 0, err } return count, nil } // 有序集合 数量 func (r *Client) ZCard(key string) (int64, error) { count, err := r.client.ZCard(key).Result() if err != nil { log.Error(fmt.Sprintf("ZCard failed %+v:", err)) return 0, err } return count, nil } // ZScore 获取元素分数 func (r *Client) ZScore(key, member string) (float64, error) { data, err := r.client.ZScore(key, member).Result() if err != nil { //log.Error(fmt.Sprintf("ZScore failed %+v:", err)) return 0, err } return data, nil } // ZCount 统计分数区间的元素个数 func (r *Client) ZCount(key, min, max string) (int64, error) { data, err := r.client.ZCount(key, min, max).Result() if err != nil { log.Error(fmt.Sprintf("ZCount failed %+v:", err)) return 0, err } return data, nil } // 无序集合 数量 func (r *Client) SCard(key string) (int64, error) { count, err := r.client.SCard(key).Result() if err != nil { log.Error(fmt.Sprintf("SCard failed %+v:", err)) return 0, err } return count, nil } // 返回区间成员 func (r *Client) ZRange(key string, start, end int64) ([]string, error) { data, err := r.client.ZRange(key, start, end).Result() if err != nil { log.Error(fmt.Sprintf("ZRange failed %+v:", err)) } return data, err } // ZRangeByScore 按分数取成员 func (r *Client) ZRangeByScore(key string, start, end string) ([]string, error) { z := goredis.ZRangeBy{ Min: start, Max: end, } data, err := r.client.ZRangeByScore(key, z).Result() if err != nil { log.Error(fmt.Sprintf("ZRangeByScore failed %+v:", err)) return nil, err } return data, nil } // ZRevRange 通过索引,分数从高到低 func (r *Client) ZRevRange(key string, start, stop int64) ([]string, error) { data, err := r.client.ZRevRange(key, start, stop).Result() if err != nil { log.Error(fmt.Sprintf("ZRevRange failed %+v:", err)) } return data, err } // ZRevRangeWithScores 通过索引,分数从高到低 一并返回分值 func (r *Client) ZRevRangeWithScores(key string, start, stop int64) ([]goredis.Z, error) { data, err := r.client.ZRevRangeWithScores(key, start, stop).Result() if err != nil { log.Error(fmt.Sprintf("ZRevRangeWithScores failed %+v:", err)) } return data, err } // ZRevRangeWithScores2 按分数排序获取前n个元素并返回分数 func (r *Client) ZRevRangeWithScores2(key string, start, limit int64) ([]string, map[string]float64) { stop := start + limit - 1 z, err := r.client.ZRevRangeWithScores(key, start, stop).Result() if err != nil { log.Error(fmt.Sprintf("ZRevRangeWithScores failed %+v:", err)) } var srt []string members := make(map[string]float64) for _, v := range z { srt = append(srt, fmt.Sprint(v.Member)) members[fmt.Sprint(v.Member)] = v.Score } return srt, members } // 按照元素排序 删除指定排名的元素 func (r *Client) ZRemRangeByRank(key string, start, end int64) (int64, error) { count, err := r.client.ZRemRangeByRank(key, start, end).Result() if err != nil { log.Error(fmt.Sprintf("ZRemRangeByRank failed %+v:", err)) return 0, err } return count, nil } // 按照元素排序 删除按指定的分数区间的的元素 func (r *Client) ZRemRangeByScore(key, start, end string) (int64, error) { count, err := r.client.ZRemRangeByScore(key, start, end).Result() if err != nil { log.Error(fmt.Sprintf("ZRemRangeByScore failed %+v:", err)) return 0, err } return count, nil } // ZRem 删除有序集合元素 func (r *Client) ZRem(key string, members ...interface{}) (int64, error) { count, err := r.client.ZRem(key, members...).Result() if err != nil { log.Error(fmt.Sprintf("ZRem failed %+v:", err)) return 0, err } return count, nil } // 判断元素是否存在于当前set中 func (r *Client) ZSISMember(key string, member string) bool { result, err := r.client.ZRank(key, member).Result() if err != nil { return false } return result != 0 } // 无序集合操作 向集合添加元素 func (r *Client) SAdd(key string, members ...interface{}) (int64, error) { count, err := r.client.SAdd(key, members...).Result() if err != nil { log.Error(fmt.Sprintf("SAdd failed %+v:", err)) return 0, err } return count, nil } // 获取无序集合的元素 func (r *Client) SMembers(key string) ([]string, error) { result, err := r.client.SMembers(key).Result() if err != nil { log.Error(fmt.Sprintf("SMembers failed %+v:", err)) } return result, err } // 无序集合操作 删除集合中某一元素 func (r *Client) SRem(key string, members ...interface{}) (int64, error) { count, err := r.client.SRem(key, members...).Result() if err != nil { log.Error(fmt.Sprintf("SRem failed %+v:", err)) return 0, err } return count, nil } // 无序集合操作 随机删除集合中某一元素 func (r *Client) SPop(key string, members ...interface{}) (string, error) { val, err := r.client.SPop(key).Result() if err != nil && err != goredis.Nil { log.Error(fmt.Sprintf("SPop failed %+v:", err)) } return val, err } // ScanSlice 返回集合成员 func (r *Client) ScanSlice(key string, container interface{}) error { if err := r.client.SMembers(key).ScanSlice(container); err != nil { log.Error(fmt.Sprintf("ScanSlice failed %+v:", err)) return err } return nil } // 判断元素是否是集合中的成员 func (r *Client) SISMember(key string, members interface{}) (bool, error) { result, err := r.client.SIsMember(key, members).Result() if err != nil { log.Error(fmt.Sprintf("SAdd failed %+v:", err)) return false, err } return result, nil } // 随机从集合中的选取成员 func (r *Client) SRandMember(key string) (string, error) { result, err := r.client.SRandMember(key).Result() if err != nil { log.Error(fmt.Sprintf("SRandMember failed %+v:", err)) return "", err } return result, nil } // 随机从集合中的选取指定数量的成员 func (r *Client) SRandMemberN(key string, count int64) ([]string, error) { result, err := r.client.SRandMemberN(key, count).Result() if err != nil { log.Error(fmt.Sprintf("SRandMemberN failed %+v:", err)) return nil, err } return result, nil } // HMget 获取hash值 func (r *Client) HMget(key string, fields []string) ([]interface{}, error) { result, err := r.client.HMGet(key, fields...).Result() if err != nil { log.Error(fmt.Sprintf("HMget failed %+v:", err)) return nil, err } return result, nil } // Hget 获取hash值 func (r *Client) Hget(key string, field string) (string, error) { result, err := r.client.HGet(key, field).Result() if err != nil { log.Error(fmt.Sprintf("Hget failed %+v:", err)) return "", err } return result, nil } // HMset 设置hash值 func (r *Client) HMset(key string, fields map[string]interface{}) error { if _, err := r.client.HMSet(key, fields).Result(); err != nil { log.Error(fmt.Sprintf("HMset failed %+v:", err)) return err } return nil } // HDel 删除hash多个键值 func (r *Client) HDel(key string, fields ...string) error { if _, err := r.client.HDel(key, fields...).Result(); err != nil { log.Error(fmt.Sprintf("HDel failed %+v:", err)) return err } return nil } // 获取 哈希表的keys func (r *Client) Hkeys(key string) []string { result, err := r.client.HKeys(key).Result() if err != nil { log.Error(fmt.Sprintf("Hkeys failed %+v:", err)) return nil } return result } // Exists 检查给定 key 是否存在 func (r *Client) Exists(keys ...string) bool { status, err := r.client.Exists(keys...).Result() if err != nil { log.Error(fmt.Sprintf("Exists failed %+v:", err)) return false } return status == 1 } // 增加对应的键值 并返回增加后的结果 func (r *Client) Incr(key string) int64 { result, err := r.client.Incr(key).Result() if err != nil { log.Error(fmt.Sprintf("Incr failed %+v:", err)) return 0 } return result } // 增加对应的键值 并返回增加后的结果 func (r *Client) IncrBy(key string, num int64, expire time.Duration) int64 { result, err := r.client.IncrBy(key, num).Result() if err != nil { log.Error(fmt.Sprintf("IncrBy failed %+v:", err)) return 0 } if expire != 0 { r.client.Expire(key, expire) } return result } // 将字符数组转换为 redis member func Convert2RedisMemForNoScore(src []string) []Member { if len(src) == 0 { return nil } members := make([]Member, 0, len(src)) for _, v := range src { if v != "" { members = append(members, Member{Member: v, Score: 0}) } } return members } // 将字符数组转换为 redis member func Convert2RedisMem(src string) Member { return Member{Member: src} } // ping func (r *Client) Ping() (*string, error) { data, err := r.client.Ping().Result() if err != nil { if err == goredis.Nil { return nil, nil } return nil, err } return &data, nil } func (r *Client) GetWithJson2Any(key string, val any) error { rv := reflect.ValueOf(val) if rv.Kind() != reflect.Ptr { return errors.New("[val] params must be a pointer") } v, err := r.client.Get(key).Bytes() if err != nil { return err } if v == nil { return goredis.Nil } return json.Unmarshal(v, val) } func (r *Client) SetWithAny2Json(key string, val any, exp time.Duration) error { v, err := json.Marshal(val) if err != nil { return err } return r.client.Set(key, string(v), exp).Err() }