package redisdao import ( "context" "fmt" "time" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/global" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/redismodel" "github.com/redis/go-redis/v9" ) // likeSetTTL 点赞集合 key 的过期时间,避免长期驻留导致与 MySQL 弱一致漂移。 const likeSetTTL = 7 * 24 * time.Hour // LikeAdd 用户点赞(like_type + target_id 分桶,成员为 user_id) func LikeAdd(ctx context.Context, likeType int8, targetID, userID int64) error { ctx, span := global.Tracer.Start(ctx, "redisdao.LikeAdd") defer span.End() key := fmt.Sprintf(redismodel.KeyLikeSet, likeType, targetID) if err := global.RedisEngine.SAdd(ctx, key, userID).Err(); err != nil { span.RecordError(err) return err } // 设置 TTL(best-effort)。 _ = global.RedisEngine.Expire(ctx, key, likeSetTTL).Err() return nil } // LikeRemove 用户取消点赞 func LikeRemove(ctx context.Context, likeType int8, targetID, userID int64) error { ctx, span := global.Tracer.Start(ctx, "redisdao.LikeRemove") defer span.End() key := fmt.Sprintf(redismodel.KeyLikeSet, likeType, targetID) if err := global.RedisEngine.SRem(ctx, key, userID).Err(); err != nil { span.RecordError(err) return err } return nil } // LikeIsMember 判断用户是否已点赞;集合 key 不存在(缓存过期/冷启动)时返回 redis.Nil, // 由调用方回落 MySQL 以区分「未命中」与「确实未点赞」。 func LikeIsMember(ctx context.Context, likeType int8, targetID, userID int64) (bool, error) { ctx, span := global.Tracer.Start(ctx, "redisdao.LikeIsMember") defer span.End() key := fmt.Sprintf(redismodel.KeyLikeSet, likeType, targetID) exists, err := global.RedisEngine.Exists(ctx, key).Result() if err != nil { span.RecordError(err) return false, err } if exists == 0 { return false, redis.Nil } ok, err := global.RedisEngine.SIsMember(ctx, key, userID).Result() if err != nil { span.RecordError(err) return false, err } return ok, nil } // LikeCount 获取点赞总数 func LikeCount(ctx context.Context, likeType int8, targetID int64) (int64, error) { ctx, span := global.Tracer.Start(ctx, "redisdao.LikeCount") defer span.End() key := fmt.Sprintf(redismodel.KeyLikeSet, likeType, targetID) cnt, err := global.RedisEngine.SCard(ctx, key).Result() if err != nil { span.RecordError(err) return 0, err } return cnt, nil }