| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- 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
- }
|