daShangDao_kfzgw-info/redis/redis.go
97694732@qq.com ac2a39742d 各种修改
2026-06-11 13:21:55 +08:00

676 lines
18 KiB
Go
Raw Permalink 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 main
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/redis/go-redis/v9"
)
// RedisClient Redis客户端结构体
type RedisClient struct {
Client *redis.Client
Ctx context.Context
}
// RedisConfig Redis配置结构体
type RedisConfig struct {
Addr string // 服务器地址:端口
Password string // 密码
DB int // 数据库编号
PoolSize int // 连接池大小
MinIdleConns int // 最小空闲连接数
DialTimeout time.Duration // 连接超时
ReadTimeout time.Duration // 读取超时
WriteTimeout time.Duration // 写入超时
PoolTimeout time.Duration // 获取连接超时
}
// NewRedisClient 创建新的Redis客户端
func NewRedisClient(config *RedisConfig) *RedisClient {
if config == nil {
// 默认配置 - 根据您的需求设置
config = &RedisConfig{
Addr: "36.212.20.113:7963",
Password: "",
DB: 2,
PoolSize: 10,
MinIdleConns: 5,
DialTimeout: 5 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
PoolTimeout: 4 * time.Second,
}
}
rdb := redis.NewClient(&redis.Options{
Addr: config.Addr,
Password: config.Password,
DB: config.DB,
PoolSize: config.PoolSize,
MinIdleConns: config.MinIdleConns,
DialTimeout: config.DialTimeout,
ReadTimeout: config.ReadTimeout,
WriteTimeout: config.WriteTimeout,
PoolTimeout: config.PoolTimeout,
})
return &RedisClient{
Client: rdb,
Ctx: context.Background(),
}
}
// Close 关闭Redis连接
func (r *RedisClient) Close() error {
return r.Client.Close()
}
// Ping 测试连接
func (r *RedisClient) Ping() error {
pong, err := r.Client.Ping(r.Ctx).Result()
if err != nil {
return fmt.Errorf("Redis连接失败: %v", err)
}
log.Printf("Redis连接成功: %s", pong)
return nil
}
// ==================== 字符串操作 ====================
// Set 设置键值对
func (r *RedisClient) Set(key string, value interface{}, expiration time.Duration) error {
err := r.Client.Set(r.Ctx, key, value, expiration).Err()
if err != nil {
return fmt.Errorf("设置键 %s 失败: %v", key, err)
}
return nil
}
// Get 获取字符串值
func (r *RedisClient) Get(key string) (string, error) {
val, err := r.Client.Get(r.Ctx, key).Result()
if err == redis.Nil {
return "", fmt.Errorf("键 %s 不存在", key)
} else if err != nil {
return "", fmt.Errorf("获取键 %s 失败: %v", key, err)
}
return val, nil
}
// GetInt 获取整数值
func (r *RedisClient) GetInt(key string) (int, error) {
val, err := r.Client.Get(r.Ctx, key).Int()
if err == redis.Nil {
return 0, fmt.Errorf("键 %s 不存在", key)
} else if err != nil {
return 0, fmt.Errorf("获取键 %s 失败: %v", key, err)
}
return val, nil
}
// GetInt64 获取64位整数值
func (r *RedisClient) GetInt64(key string) (int64, error) {
val, err := r.Client.Get(r.Ctx, key).Int64()
if err == redis.Nil {
return 0, fmt.Errorf("键 %s 不存在", key)
} else if err != nil {
return 0, fmt.Errorf("获取键 %s 失败: %v", key, err)
}
return val, nil
}
// GetFloat64 获取浮点数值
func (r *RedisClient) GetFloat64(key string) (float64, error) {
val, err := r.Client.Get(r.Ctx, key).Float64()
if err == redis.Nil {
return 0, fmt.Errorf("键 %s 不存在", key)
} else if err != nil {
return 0, fmt.Errorf("获取键 %s 失败: %v", key, err)
}
return val, nil
}
// GetBool 获取布尔值
func (r *RedisClient) GetBool(key string) (bool, error) {
val, err := r.Client.Get(r.Ctx, key).Bool()
if err == redis.Nil {
return false, fmt.Errorf("键 %s 不存在", key)
} else if err != nil {
return false, fmt.Errorf("获取键 %s 失败: %v", key, err)
}
return val, nil
}
// SetNX 只有当键不存在时设置值
func (r *RedisClient) SetNX(key string, value interface{}, expiration time.Duration) (bool, error) {
success, err := r.Client.SetNX(r.Ctx, key, value, expiration).Result()
if err != nil {
return false, fmt.Errorf("SetNX操作失败: %v", err)
}
return success, nil
}
// SetXX 只有当键存在时设置值
func (r *RedisClient) SetXX(key string, value interface{}, expiration time.Duration) (bool, error) {
success, err := r.Client.SetXX(r.Ctx, key, value, expiration).Result()
if err != nil {
return false, fmt.Errorf("SetXX操作失败: %v", err)
}
return success, nil
}
// MSet 批量设置键值对
func (r *RedisClient) MSet(values map[string]interface{}) error {
pairs := make([]interface{}, 0, len(values)*2)
for k, v := range values {
pairs = append(pairs, k, v)
}
err := r.Client.MSet(r.Ctx, pairs...).Err()
if err != nil {
return fmt.Errorf("批量设置失败: %v", err)
}
return nil
}
// MGet 批量获取值
func (r *RedisClient) MGet(keys ...string) ([]interface{}, error) {
vals, err := r.Client.MGet(r.Ctx, keys...).Result()
if err != nil {
return nil, fmt.Errorf("批量获取失败: %v", err)
}
return vals, nil
}
// Incr 自增1
func (r *RedisClient) Incr(key string) (int64, error) {
val, err := r.Client.Incr(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("自增失败: %v", err)
}
return val, nil
}
// IncrBy 自增指定值
func (r *RedisClient) IncrBy(key string, value int64) (int64, error) {
val, err := r.Client.IncrBy(r.Ctx, key, value).Result()
if err != nil {
return 0, fmt.Errorf("自增 %d 失败: %v", value, err)
}
return val, nil
}
// Decr 自减1
func (r *RedisClient) Decr(key string) (int64, error) {
val, err := r.Client.Decr(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("自减失败: %v", err)
}
return val, nil
}
// DecrBy 自减指定值
func (r *RedisClient) DecrBy(key string, value int64) (int64, error) {
val, err := r.Client.DecrBy(r.Ctx, key, value).Result()
if err != nil {
return 0, fmt.Errorf("自减 %d 失败: %v", value, err)
}
return val, nil
}
// Append 追加字符串
func (r *RedisClient) Append(key, value string) (int64, error) {
length, err := r.Client.Append(r.Ctx, key, value).Result()
if err != nil {
return 0, fmt.Errorf("追加字符串失败: %v", err)
}
return length, nil
}
// StrLen 获取字符串长度
func (r *RedisClient) StrLen(key string) (int64, error) {
length, err := r.Client.StrLen(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("获取字符串长度失败: %v", err)
}
return length, nil
}
// ==================== 键操作 ====================
// Exists 检查键是否存在
func (r *RedisClient) Exists(keys ...string) (int64, error) {
count, err := r.Client.Exists(r.Ctx, keys...).Result()
if err != nil {
return 0, fmt.Errorf("检查键是否存在失败: %v", err)
}
return count, nil
}
// Del 删除键
func (r *RedisClient) Del(keys ...string) (int64, error) {
count, err := r.Client.Del(r.Ctx, keys...).Result()
if err != nil {
return 0, fmt.Errorf("删除键失败: %v", err)
}
return count, nil
}
// Expire 设置过期时间
func (r *RedisClient) Expire(key string, expiration time.Duration) (bool, error) {
success, err := r.Client.Expire(r.Ctx, key, expiration).Result()
if err != nil {
return false, fmt.Errorf("设置过期时间失败: %v", err)
}
return success, nil
}
// TTL 获取剩余过期时间
func (r *RedisClient) TTL(key string) (time.Duration, error) {
ttl, err := r.Client.TTL(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("获取过期时间失败: %v", err)
}
return ttl, nil
}
// Persist 移除过期时间
func (r *RedisClient) Persist(key string) (bool, error) {
success, err := r.Client.Persist(r.Ctx, key).Result()
if err != nil {
return false, fmt.Errorf("移除过期时间失败: %v", err)
}
return success, nil
}
// Type 获取键类型
func (r *RedisClient) Type(key string) (string, error) {
typeStr, err := r.Client.Type(r.Ctx, key).Result()
if err != nil {
return "", fmt.Errorf("获取键类型失败: %v", err)
}
return typeStr, nil
}
// Keys 查找所有匹配的键
func (r *RedisClient) Keys(pattern string) ([]string, error) {
keys, err := r.Client.Keys(r.Ctx, pattern).Result()
if err != nil {
return nil, fmt.Errorf("查找键失败: %v", err)
}
return keys, nil
}
// RandomKey 随机获取一个键
func (r *RedisClient) RandomKey() (string, error) {
key, err := r.Client.RandomKey(r.Ctx).Result()
if err != nil {
return "", fmt.Errorf("随机获取键失败: %v", err)
}
return key, nil
}
// Rename 重命名键
func (r *RedisClient) Rename(key, newKey string) error {
err := r.Client.Rename(r.Ctx, key, newKey).Err()
if err != nil {
return fmt.Errorf("重命名键失败: %v", err)
}
return nil
}
// RenameNX 只有当新键不存在时重命名
func (r *RedisClient) RenameNX(key, newKey string) (bool, error) {
success, err := r.Client.RenameNX(r.Ctx, key, newKey).Result()
if err != nil {
return false, fmt.Errorf("重命名键失败: %v", err)
}
return success, nil
}
// ==================== Hash操作 ====================
// HSet 设置Hash字段
func (r *RedisClient) HSet(key string, values ...interface{}) error {
err := r.Client.HSet(r.Ctx, key, values...).Err()
if err != nil {
return fmt.Errorf("设置Hash失败: %v", err)
}
return nil
}
// HGet 获取Hash字段
func (r *RedisClient) HGet(key, field string) (string, error) {
val, err := r.Client.HGet(r.Ctx, key, field).Result()
if err == redis.Nil {
return "", fmt.Errorf("字段 %s 不存在", field)
} else if err != nil {
return "", fmt.Errorf("获取Hash字段失败: %v", err)
}
return val, nil
}
// HGetAll 获取所有Hash字段
func (r *RedisClient) HGetAll(key string) (map[string]string, error) {
vals, err := r.Client.HGetAll(r.Ctx, key).Result()
if err != nil {
return nil, fmt.Errorf("获取所有Hash字段失败: %v", err)
}
return vals, nil
}
// HDel 删除Hash字段
func (r *RedisClient) HDel(key string, fields ...string) (int64, error) {
count, err := r.Client.HDel(r.Ctx, key, fields...).Result()
if err != nil {
return 0, fmt.Errorf("删除Hash字段失败: %v", err)
}
return count, nil
}
// HExists 检查Hash字段是否存在
func (r *RedisClient) HExists(key, field string) (bool, error) {
exists, err := r.Client.HExists(r.Ctx, key, field).Result()
if err != nil {
return false, fmt.Errorf("检查Hash字段失败: %v", err)
}
return exists, nil
}
// HKeys 获取所有Hash字段名
func (r *RedisClient) HKeys(key string) ([]string, error) {
keys, err := r.Client.HKeys(r.Ctx, key).Result()
if err != nil {
return nil, fmt.Errorf("获取Hash字段名失败: %v", err)
}
return keys, nil
}
// HVals 获取所有Hash字段值
func (r *RedisClient) HVals(key string) ([]string, error) {
vals, err := r.Client.HVals(r.Ctx, key).Result()
if err != nil {
return nil, fmt.Errorf("获取Hash字段值失败: %v", err)
}
return vals, nil
}
// HLen 获取Hash字段数量
func (r *RedisClient) HLen(key string) (int64, error) {
count, err := r.Client.HLen(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("获取Hash字段数量失败: %v", err)
}
return count, nil
}
// HIncrBy Hash字段自增
func (r *RedisClient) HIncrBy(key, field string, incr int64) (int64, error) {
val, err := r.Client.HIncrBy(r.Ctx, key, field, incr).Result()
if err != nil {
return 0, fmt.Errorf("Hash字段自增失败: %v", err)
}
return val, nil
}
// ==================== List操作 ====================
// LPush 从左侧插入列表
func (r *RedisClient) LPush(key string, values ...interface{}) (int64, error) {
count, err := r.Client.LPush(r.Ctx, key, values...).Result()
if err != nil {
return 0, fmt.Errorf("LPush失败: %v", err)
}
return count, nil
}
// RPush 从右侧插入列表
func (r *RedisClient) RPush(key string, values ...interface{}) (int64, error) {
count, err := r.Client.RPush(r.Ctx, key, values...).Result()
if err != nil {
return 0, fmt.Errorf("RPush失败: %v", err)
}
return count, nil
}
// LPop 从左侧弹出元素
func (r *RedisClient) LPop(key string) (string, error) {
val, err := r.Client.LPop(r.Ctx, key).Result()
if err == redis.Nil {
return "", fmt.Errorf("列表为空")
} else if err != nil {
return "", fmt.Errorf("LPop失败: %v", err)
}
return val, nil
}
// RPop 从右侧弹出元素
func (r *RedisClient) RPop(key string) (string, error) {
val, err := r.Client.RPop(r.Ctx, key).Result()
if err == redis.Nil {
return "", fmt.Errorf("列表为空")
} else if err != nil {
return "", fmt.Errorf("RPop失败: %v", err)
}
return val, nil
}
// LLen 获取列表长度
func (r *RedisClient) LLen(key string) (int64, error) {
length, err := r.Client.LLen(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("获取列表长度失败: %v", err)
}
return length, nil
}
// LRange 获取列表范围
func (r *RedisClient) LRange(key string, start, stop int64) ([]string, error) {
vals, err := r.Client.LRange(r.Ctx, key, start, stop).Result()
if err != nil {
return nil, fmt.Errorf("获取列表范围失败: %v", err)
}
return vals, nil
}
// ==================== Set操作 ====================
// SAdd 添加集合元素
func (r *RedisClient) SAdd(key string, members ...interface{}) (int64, error) {
count, err := r.Client.SAdd(r.Ctx, key, members...).Result()
if err != nil {
return 0, fmt.Errorf("SAdd失败: %v", err)
}
return count, nil
}
// SMembers 获取所有集合成员
func (r *RedisClient) SMembers(key string) ([]string, error) {
members, err := r.Client.SMembers(r.Ctx, key).Result()
if err != nil {
return nil, fmt.Errorf("获取集合成员失败: %v", err)
}
return members, nil
}
// SIsMember 检查是否是集合成员
func (r *RedisClient) SIsMember(key string, member interface{}) (bool, error) {
exists, err := r.Client.SIsMember(r.Ctx, key, member).Result()
if err != nil {
return false, fmt.Errorf("检查集合成员失败: %v", err)
}
return exists, nil
}
// SCard 获取集合基数
func (r *RedisClient) SCard(key string) (int64, error) {
count, err := r.Client.SCard(r.Ctx, key).Result()
if err != nil {
return 0, fmt.Errorf("获取集合基数失败: %v", err)
}
return count, nil
}
// ==================== Sorted Set操作 ====================
// ZAdd 添加有序集合元素
func (r *RedisClient) ZAdd(key string, members ...redis.Z) (int64, error) {
count, err := r.Client.ZAdd(r.Ctx, key, members...).Result()
if err != nil {
return 0, fmt.Errorf("ZAdd失败: %v", err)
}
return count, nil
}
// ZRange 获取有序集合范围
func (r *RedisClient) ZRange(key string, start, stop int64) ([]string, error) {
vals, err := r.Client.ZRange(r.Ctx, key, start, stop).Result()
if err != nil {
return nil, fmt.Errorf("ZRange失败: %v", err)
}
return vals, nil
}
// ZRangeWithScores 获取有序集合范围和分数
func (r *RedisClient) ZRangeWithScores(key string, start, stop int64) ([]redis.Z, error) {
vals, err := r.Client.ZRangeWithScores(r.Ctx, key, start, stop).Result()
if err != nil {
return nil, fmt.Errorf("ZRangeWithScores失败: %v", err)
}
return vals, nil
}
// ZScore 获取元素分数
func (r *RedisClient) ZScore(key, member string) (float64, error) {
score, err := r.Client.ZScore(r.Ctx, key, member).Result()
if err == redis.Nil {
return 0, fmt.Errorf("元素不存在")
} else if err != nil {
return 0, fmt.Errorf("获取分数失败: %v", err)
}
return score, nil
}
// ==================== JSON序列化操作 ====================
// SetJSON 将结构体序列化为JSON并存储
func (r *RedisClient) SetJSON(key string, data interface{}, expiration time.Duration) error {
jsonData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("JSON序列化失败: %v", err)
}
return r.Set(key, jsonData, expiration)
}
// GetJSON 获取JSON并反序列化到结构体
func (r *RedisClient) GetJSON(key string, result interface{}) error {
data, err := r.Get(key)
if err != nil {
return err
}
err = json.Unmarshal([]byte(data), result)
if err != nil {
return fmt.Errorf("JSON反序列化失败: %v", err)
}
return nil
}
// ==================== 分布式锁 ====================
// TryLock 尝试获取分布式锁
func (r *RedisClient) TryLock(key string, expiration time.Duration) (bool, error) {
success, err := r.Client.SetNX(r.Ctx, key, "locked", expiration).Result()
if err != nil {
return false, fmt.Errorf("获取锁失败: %v", err)
}
return success, nil
}
// ReleaseLock 释放分布式锁
func (r *RedisClient) ReleaseLock(key string) error {
// 使用Lua脚本确保原子性操作
script := `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`
result, err := r.Client.Eval(r.Ctx, script, []string{key}, "locked").Result()
if err != nil {
return fmt.Errorf("释放锁失败: %v", err)
}
if result.(int64) == 0 {
return fmt.Errorf("锁已释放或不属于当前客户端")
}
return nil
}
// ==================== 管道操作 ====================
// Pipeline 执行管道操作
func (r *RedisClient) Pipeline(fn func(pipe redis.Pipeliner) error) error {
pipe := r.Client.Pipeline()
err := fn(pipe)
if err != nil {
return err
}
_, err = pipe.Exec(r.Ctx)
return err
}
// ==================== 事务操作 ====================
// Watch 监视键并执行事务
func (r *RedisClient) Watch(fn func(tx *redis.Tx) error, keys ...string) error {
err := r.Client.Watch(r.Ctx, fn, keys...)
if err != nil {
return fmt.Errorf("事务执行失败: %v", err)
}
return nil
}
// ==================== 发布订阅 ====================
// Publish 发布消息
func (r *RedisClient) Publish(channel string, message interface{}) error {
err := r.Client.Publish(r.Ctx, channel, message).Err()
if err != nil {
return fmt.Errorf("发布消息失败: %v", err)
}
return nil
}
// Subscribe 订阅频道
func (r *RedisClient) Subscribe(channels ...string) *redis.PubSub {
return r.Client.Subscribe(r.Ctx, channels...)
}
// ==================== 数据库操作 ====================
// SelectDB 切换数据库
// 注意go-redis/v9的Client没有直接的Select方法需要通过Do命令执行
func (r *RedisClient) SelectDB(db int) error {
// 使用Do命令执行SELECT
cmd := redis.NewCmd(r.Ctx, "SELECT", db)
err := r.Client.Process(r.Ctx, cmd)
if err != nil {
return fmt.Errorf("切换数据库到 %d 失败: %v", db, err)
}
// 检查命令执行结果
_, err = cmd.Result()
if err != nil {
return fmt.Errorf("切换数据库到 %d 失败: %v", db, err)
}
return nil
}
//// 主函数
//func main() {
//}