go-redis设置前缀
- 因为go-redis官方库中并不支持前缀所以自己想办法支持了一下
- 使用go-redis的钩子函数支持
- 注意:使用 conn := client.Conn();方法获取的连接不会走钩子函数
- 直接改变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"
)
func InitilizeGoRedis() {
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 := 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])
}
}
}
怎么读取yaml配置文件,可以看完另一篇文章
- 单元测试配置文件路径 这一篇文章里面有读取yaml文件代码
- 这下面代码是我几个包合起来的,可能会有报错自己稍微调试一下吧
package global
import (
goRedis "github.com/redis/go-redis/v9"
"os"
"gopkg.in/yaml.v2"
)
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)
}