Files
huangguo_server/common/redis/redis.go
T
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

1027 lines
26 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()
}