package service import ( "context" "encoding/json" "fmt" "time" "github.com/redis/go-redis/v9" ) // Cache Redis 缓存封装(5min TTL + 1min 空值 TTL 防穿透) type Cache struct { rdb *redis.Client ttl time.Duration emptyTTL time.Duration missedHits int64 } // NewCache 构造 func NewCache(rdb *redis.Client) *Cache { return &Cache{ rdb: rdb, ttl: 5 * time.Minute, emptyTTL: 1 * time.Minute, } } // GetJSON 取缓存 + JSON 反序列化 func (c *Cache) GetJSON(ctx context.Context, key string, dst interface{}) (bool, error) { v, err := c.rdb.Get(ctx, key).Result() if err == redis.Nil { return false, nil } if err != nil { return false, err } if v == "null" { return false, nil // 缓存穿透防护的空标记 } if err := json.Unmarshal([]byte(v), dst); err != nil { return false, err } return true, nil } // SetJSON 序列化 + 缓存(5min TTL) func (c *Cache) SetJSON(ctx context.Context, key string, value interface{}) error { b, err := json.Marshal(value) if err != nil { return err } return c.rdb.Set(ctx, key, b, c.ttl).Err() } // SetEmpty 缓存空值(1min TTL,防穿透) func (c *Cache) SetEmpty(ctx context.Context, key string) error { return c.rdb.Set(ctx, key, "null", c.emptyTTL).Err() } // CacheKey 看板缓存 key 格式 func CacheKey(rpc string, starID, userID int64) string { return fmt.Sprintf("dash:%s:%d:%d", rpc, starID, userID) }