jsonx.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package redisx
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "time"
  7. "github.com/redis/go-redis/v9"
  8. )
  9. // SetJSON 将任意结构体序列化为 JSON 存入 Redis
  10. func SetJSON(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
  11. if value == nil {
  12. return errors.New("redisx.SetJSON: value is nil")
  13. }
  14. data, err := json.Marshal(value)
  15. if err != nil {
  16. return err
  17. }
  18. return getClient().Set(ctx, key, data, ttl).Err()
  19. }
  20. // GetJSON 从 Redis 获取并反序列化为指定结构体
  21. func GetJSON[T any](ctx context.Context, key string, dest *T) error {
  22. if dest == nil {
  23. return errors.New("redisx.GetJSON: dest is nil")
  24. }
  25. val, err := getClient().Get(ctx, key).Bytes()
  26. if err != nil {
  27. if err == redis.Nil {
  28. return errors.New("redisx.GetJSON: key not found")
  29. }
  30. return err
  31. }
  32. return json.Unmarshal(val, dest)
  33. }
  34. // MustGetJSON 返回默认值版本(未命中时返回 nil)
  35. func MustGetJSON[T any](ctx context.Context, key string) *T {
  36. var out T
  37. err := GetJSON(ctx, key, &out)
  38. if err != nil {
  39. return nil
  40. }
  41. return &out
  42. }
  43. // HSetJSON 在 Hash 中存储 JSON
  44. func HSetJSON(ctx context.Context, key, field string, value interface{}) error {
  45. data, err := json.Marshal(value)
  46. if err != nil {
  47. return err
  48. }
  49. return getClient().HSet(ctx, key, field, data).Err()
  50. }
  51. // HGetJSON 从 Hash 中读取 JSON
  52. func HGetJSON[T any](ctx context.Context, key, field string, dest *T) error {
  53. val, err := getClient().HGet(ctx, key, field).Bytes()
  54. if err != nil {
  55. if err == redis.Nil {
  56. return errors.New("redisx.HGetJSON: field not found")
  57. }
  58. return err
  59. }
  60. return json.Unmarshal(val, dest)
  61. }
  62. // MGetJSON 支持批量获取多个 JSON 对象
  63. // return (items []*T, missing []string, err error)
  64. // missing为未命中的key列表
  65. func MGetJSON[T any](ctx context.Context, keys ...string) (map[string]*T, []string, error) {
  66. if len(keys) == 0 {
  67. return nil, nil, nil
  68. }
  69. results, err := getClient().MGet(ctx, keys...).Result()
  70. if err != nil {
  71. return nil, nil, err
  72. }
  73. items := make(map[string]*T)
  74. missing := make([]string, 0)
  75. for i, res := range results {
  76. k := keys[i]
  77. if res == nil {
  78. missing = append(missing, k)
  79. continue
  80. }
  81. var v T
  82. if err := json.Unmarshal([]byte(res.(string)), &v); err != nil {
  83. missing = append(missing, k)
  84. continue
  85. }
  86. items[k] = &v
  87. }
  88. return items, missing, nil
  89. }
  90. // MSetJSON 支持批量多个 JSON 对象
  91. func MSetJSON[T any](ctx context.Context, kvs map[string]*T, ttl time.Duration) error {
  92. if len(kvs) == 0 {
  93. return nil
  94. }
  95. // 如果 ttl == 0,可以直接用 MSet
  96. if ttl == 0 {
  97. args := make([]any, 0, len(kvs)*2)
  98. for k, v := range kvs {
  99. b, err := json.Marshal(v)
  100. if err != nil {
  101. return err
  102. }
  103. args = append(args, k, b)
  104. }
  105. return MSet(ctx, args...)
  106. }
  107. // 否则使用 pipeline 设置过期时间
  108. _, err := Pipeline(ctx, func(p redis.Pipeliner) error {
  109. for k, v := range kvs {
  110. if v == nil {
  111. continue
  112. }
  113. b, err := json.Marshal(v)
  114. if err != nil {
  115. return err
  116. }
  117. p.Set(ctx, k, b, ttl)
  118. }
  119. return nil
  120. })
  121. return err
  122. }