企业网站建设应具备的功能免费二维码制作网站
企业网站建设应具备的功能,免费二维码制作网站,中国网络优化推广,电脑网站 手机网站 微信网站一、前言#xff1a;为什么点赞排行榜不能直接查数据库#xff1f;在短视频、社区、电商等产品中#xff0c;“点赞排行榜”是提升用户活跃度的关键功能。
但如果你这样实现#xff1a;SELECT user_id, SUM(like_count)
FROM posts
GROUP BY user_id
ORDER BY SUM(like_…一、前言为什么点赞排行榜不能直接查数据库在短视频、社区、电商等产品中“点赞排行榜”是提升用户活跃度的关键功能。但如果你这样实现SELECT user_id, SUM(like_count) FROM posts GROUP BY user_id ORDER BY SUM(like_count) DESC LIMIT 10;那么在百万级数据 高并发场景下你会遇到数据库 CPU 飙升接口响应超时2s缓存穿透/雪崩风险Redis 的有序集合ZSet正是为此类场景而生本文将手把手教你用 Redis ZSet 实现毫秒级响应的点赞排行榜并支持实时更新、分页查询、用户排名等高级功能。二、为什么选择 Redis ZSet特性说明✅自动排序按 score点赞数自动维护顺序✅O(log N) 插入/更新百万数据毫秒级响应✅范围查询高效ZREVRANGE直接取 Top N✅支持成员唯一同一用户只存一条记录✅内存存储读写速度极快一句话总结ZSet 排行榜的天然数据结构三、核心设计思路1. 数据模型Keylike_ranking全局点赞排行榜Memberuser_idScore该用户的总点赞数2. 更新时机用户发布内容被点赞 → 累加作者点赞数内容被取消点赞 → 扣减作者点赞数3. 查询能力获取 Top 10 用户查询某用户当前排名分页拉取排行榜如第 2 页四、Spring Boot 完整实现步骤 1定义排行榜服务接口public interface LikeRankingService { void incrementLikeCount(Long userId, long delta); ListRankingUser getTopN(int n); Long getUserRank(Long userId); ListRankingUser getRankingPage(int page, int size); }步骤 2Redis ZSet 实现Service public class RedisLikeRankingService implements LikeRankingService { Autowired private StringRedisTemplate redisTemplate; private static final String RANKING_KEY like_ranking; Override public void incrementLikeCount(Long userId, long delta) { // ZINCRBY key increment member redisTemplate.opsForZSet().incrementScore(RANKING_KEY, userId.toString(), delta); // 可选设置过期时间防内存无限增长如 30 天 // redisTemplate.expire(RANKING_KEY, 30, TimeUnit.DAYS); } Override public ListRankingUser getTopN(int n) { // ZREVRANGE key 0 N-1 WITHSCORES 倒序score 从高到低 SetZSetOperations.TypedTupleString tuples redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, n - 1); return convertToRankingUsers(tuples); } Override public Long getUserRank(Long userId) { // ZREVRANK key member 返回排名从 0 开始 Long rank redisTemplate.opsForZSet().reverseRank(RANKING_KEY, userId.toString()); return rank null ? -1 : rank 1; // 转为 1-based } Override public ListRankingUser getRankingPage(int page, int size) { long start (long) (page - 1) * size; long end start size - 1; SetZSetOperations.TypedTupleString tuples redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, start, end); return convertToRankingUsers(tuples); } private ListRankingUser convertToRankingUsers( SetZSetOperations.TypedTupleString tuples) { if (tuples null || tuples.isEmpty()) { return Collections.emptyList(); } return tuples.stream() .map(tuple - new RankingUser( Long.parseLong(tuple.getValue()), tuple.getScore().longValue() )) .collect(Collectors.toList()); } }注意reverseRank返回的是从高到低的排名0 表示第 1 名步骤 3与点赞功能联动关键当内容被点赞时不仅要更新内容的点赞数还要累加作者的总点赞数Service public class LikeService { Autowired private LikeRankingService rankingService; Autowired private ContentService contentService; public boolean like(Long userId, Long contentId) { // ... 校验、防重、更新内容点赞数略 // 获取内容作者 Long authorId contentService.getAuthorId(contentId); // 累加作者总点赞数1 rankingService.incrementLikeCount(authorId, 1); return true; } public boolean unlike(Long userId, Long contentId) { // ... 取消逻辑 Long authorId contentService.getAuthorId(contentId); rankingService.incrementLikeCount(authorId, -1); // -1 return true; } }✅优势每次只更新一个用户 scoreO(log N)性能极高步骤 4Controller 层提供 APIRestController public class RankingController { Autowired private LikeRankingService rankingService; // 获取 Top 10 GetMapping(/ranking/top10) public ResultListRankingUser getTop10() { return Result.success(rankingService.getTopN(10)); } // 查询我的排名 GetMapping(/ranking/my) public ResultMapString, Object myRank(RequestHeader(userId) Long userId) { Long rank rankingService.getUserRank(userId); long likeCount rankingService.getLikeCount(userId); // 可从 ZSet 获取 return Result.success(Map.of(rank, rank, likeCount, likeCount)); } // 分页排行榜用于“查看更多” GetMapping(/ranking/page) public ResultListRankingUser getPage( RequestParam(defaultValue 1) int page, RequestParam(defaultValue 20) int size) { if (page 1 || size 50) { return Result.fail(参数非法); } return Result.success(rankingService.getRankingPage(page, size)); } }五、高级优化技巧 1.冷热分离热门用户Top 1万常驻内存冷门用户定期归档到 DBZSet 中移除 2.防止 Score 溢出使用Long存储但需监控最大值Redis ZSet score 是 double但整数安全范围约 2^53 3.排行榜缓存预热应用启动时加载 Top 100 到本地缓存Caffeine减少 Redis 访问 4.多维度排行榜全局榜like_ranking日榜like_ranking:20251103周榜like_ranking:week:45String dailyKey like_ranking: LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);六、对比方案为什么不用数据库方案响应时间QPS实时性扩展性MySQL ORDER BY500ms 100差需定时聚合差Redis ZSet 5ms 10,000实时极好结论排行榜类场景首选 Redis ZSet七、结语感谢您的阅读如果你有任何疑问或想要分享的经验请在评论区留言交流