package redisx import ( "context" "encoding/json" "errors" "time" "github.com/redis/go-redis/v9" ) // SetJSON 将任意结构体序列化为 JSON 存入 Redis func SetJSON(ctx context.Context, key string, value interface{}, ttl time.Duration) error { if value == nil { return errors.New("redisx.SetJSON: value is nil") } data, err := json.Marshal(value) if err != nil { return err } return getClient().Set(ctx, key, data, ttl).Err() } // GetJSON 从 Redis 获取并反序列化为指定结构体 func GetJSON[T any](ctx context.Context, key string, dest *T) error { if dest == nil { return errors.New("redisx.GetJSON: dest is nil") } val, err := getClient().Get(ctx, key).Bytes() if err != nil { if err == redis.Nil { return errors.New("redisx.GetJSON: key not found") } return err } return json.Unmarshal(val, dest) } // MustGetJSON 返回默认值版本(未命中时返回 nil) func MustGetJSON[T any](ctx context.Context, key string) *T { var out T err := GetJSON(ctx, key, &out) if err != nil { return nil } return &out } // HSetJSON 在 Hash 中存储 JSON func HSetJSON(ctx context.Context, key, field string, value interface{}) error { data, err := json.Marshal(value) if err != nil { return err } return getClient().HSet(ctx, key, field, data).Err() } // HGetJSON 从 Hash 中读取 JSON func HGetJSON[T any](ctx context.Context, key, field string, dest *T) error { val, err := getClient().HGet(ctx, key, field).Bytes() if err != nil { if err == redis.Nil { return errors.New("redisx.HGetJSON: field not found") } return err } return json.Unmarshal(val, dest) } // MGetJSON 支持批量获取多个 JSON 对象 // return (items []*T, missing []string, err error) // missing为未命中的key列表 func MGetJSON[T any](ctx context.Context, keys ...string) (map[string]*T, []string, error) { if len(keys) == 0 { return nil, nil, nil } results, err := getClient().MGet(ctx, keys...).Result() if err != nil { return nil, nil, err } items := make(map[string]*T) missing := make([]string, 0) for i, res := range results { k := keys[i] if res == nil { missing = append(missing, k) continue } var v T if err := json.Unmarshal([]byte(res.(string)), &v); err != nil { missing = append(missing, k) continue } items[k] = &v } return items, missing, nil } // MSetJSON 支持批量多个 JSON 对象 func MSetJSON[T any](ctx context.Context, kvs map[string]*T, ttl time.Duration) error { if len(kvs) == 0 { return nil } // 如果 ttl == 0,可以直接用 MSet if ttl == 0 { args := make([]any, 0, len(kvs)*2) for k, v := range kvs { b, err := json.Marshal(v) if err != nil { return err } args = append(args, k, b) } return MSet(ctx, args...) } // 否则使用 pipeline 设置过期时间 _, err := Pipeline(ctx, func(p redis.Pipeliner) error { for k, v := range kvs { if v == nil { continue } b, err := json.Marshal(v) if err != nil { return err } p.Set(ctx, k, b, ttl) } return nil }) return err }