go-redis设置前缀

go-redis设置前缀

  1. 因为go-redis官方库中并不支持前缀所以自己想办法支持了一下
  2. 使用go-redis的钩子函数支持
  3. 注意:使用 conn := client.Conn();方法获取的连接不会走钩子函数
  4. 直接改变args变量即可,因为内存地址是一样

初始化redis

package initilize

import (
	"context"
	"net"
	"xxxx/global"
	"strings"
	"time"

	"github.com/redis/go-redis/v9"
	"github.com/samber/lo"
	"github.com/spf13/cast"
)

/**
 * 初始化redis,并赋值给全局变量
 */

func InitilizeGoRedis() {
	// 创建redis连接池
	conf := global.CONFIG.Redis
	rdb := redis.NewClient(&redis.Options{
		Addr:         conf.Addr + ":" + conf.Port,
		Password:     conf.Password,
		DB:           conf.Db,
		MaxIdleConns: conf.MaxIdle,
		MinIdleConns: conf.MinIdle,
		PoolTimeout:  time.Duration(conf.Timeout) * time.Second,
		PoolSize:     conf.Active,
	})
	rdb.AddHook(Hook1{})
	global.RedisClient = rdb
}

// 钩子函数中定义的全局标志
type contextKey string

const skipPrefixKey contextKey = "skipPrefix"

// 定义一个上下文辅助函数
func WithSkipPrefix(ctx context.Context) context.Context {
	return context.WithValue(ctx, skipPrefixKey, true)
}

func shouldSkipPrefix(ctx context.Context) bool {
	value := ctx.Value(skipPrefixKey)
	skip, ok := value.(bool)
	return ok && skip
}

// 允许适配前缀的命令
var commandsWithPrefix = []string{
	"GET", "SET", "EXISTS", "DEL", "TYPE",
	"RPUSH", "LPOP", "RPOP", "LLEN", "LRANGE",
	"SADD", "SREM", "SISMEMBER", "SMEMBERS", "SCARD",
	"HSET", "HMSET", "HGET", "HGETALL",
	"ZADD", "ZRANGE", "ZRANGEBYSCORE", "ZREVRANGEBYSCORE", "ZREM",
	"INCR", "INCRBY", "INCRBYFLOAT",
	"WATCH", "MULTI", "EXEC", "EXPIRE",
}

type Hook1 struct{}

func (Hook1) DialHook(next redis.DialHook) redis.DialHook {
	return func(ctx context.Context, network, addr string) (net.Conn, error) {
		return next(ctx, network, addr)
	}
}

func (Hook1) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
	return func(ctx context.Context, cmd redis.Cmder) error {
		if !shouldSkipPrefix(ctx) {
			addPrefixToArgs(ctx, cmd)
		}
		return next(ctx, cmd)
	}
}

func (Hook1) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
	return func(ctx context.Context, cmds []redis.Cmder) error {
		if !shouldSkipPrefix(ctx) {
			for _, cmd := range cmds {
				addPrefixToArgs(ctx, cmd)
			}
		}
		return next(ctx, cmds)
	}
}

// 公共前缀处理函数
func addPrefixToArgs(ctx context.Context, cmd redis.Cmder) {
	// 直接改变args变量即可,因为内存地址是一样
	args := cmd.Args()
	if len(args) <= 1 {
		return
	}

	name := strings.ToUpper(cmd.Name())
	switch name {
	case "MGET", "DEL":
		for i := 1; i < len(args); i++ {
			args[i] = global.CONFIG.Redis.Prefix + ":" + cast.ToString(args[i])
		}
	case "MSET":
		for i := 1; i < len(args); i += 2 {
			args[i] = global.CONFIG.Redis.Prefix + ":" + cast.ToString(args[i])
		}
	case "SCAN":
		if len(args) > 2 {
			for i := 2; i < len(args); i += 2 {
				if args[i] == "match" && i+1 < len(args) {
					args[i+1] = global.CONFIG.Redis.Prefix + ":" + cast.ToString(args[i+1])
					break
				}
			}
		}
	default:
		if lo.IndexOf[string](commandsWithPrefix, name) != -1 {
			args[1] = global.CONFIG.Redis.Prefix + ":" + cast.ToString(args[1])
		}
	}
	// fmt.Println(cmd)
}

怎么读取yaml配置文件,可以看完另一篇文章

  1. 单元测试配置文件路径 这一篇文章里面有读取yaml文件代码
  2. 这下面代码是我几个包合起来的,可能会有报错自己稍微调试一下吧
package global
import (
	goRedis "github.com/redis/go-redis/v9"
	"os"
	"gopkg.in/yaml.v2"
)

// 这个结构体本来在config包的,但是为了写文档就单独提出来了
type Config struct {
	Db     Db     `yaml:"db"`
	Redis  Redis  `yaml:"redis"`
}

type Redis struct {
	Addr     string `yaml:"addr"`
	Password string `yaml:"password"`
	Db       int    `yaml:"db"`
	Port     string `yaml:"port"`
	Size     int    `yaml:"size"`
	Auth     bool   `yaml:"auth"`
	MaxIdle  int    `yaml:"max-idle-conn"`
	MinIdle  int    `yaml:"min-idle-conn"`
	Active   int    `yaml:"active-idle-conn"`
	Timeout  int    `yaml:"timeout"`
	Prefix   string `yaml:"prefix"`
}

var (
	CONFIG      Config
	RedisClient *goRedis.Client
)

func init() {
	// 加载配置文件
	configPath := rootDir + "/config/application.yaml"
	yamlFile, err := os.ReadFile(configPath)
	if err != nil {
		log.Panicf("Failed to read file , cause is %s", err.Error())
	}
	config := config.Config{}
	err = yaml.Unmarshal(yamlFile, &config)
	global.CONFIG = config
	if err != nil {
		fmt.Println(err.Error())
	}
}

使用go-redis,官方文档

package main

func main(){
	_, err := global.RedisClient.MSet(context.Background(), "key1", "123", "key2", "321").Result()
	if err != nil {
		fmt.Println(err)
	}
	res, err := global.RedisClient.MGet(context.Background(), "key1", "key2").Result()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(res)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值