redis(zset使用)使用场景案例

redis(zset使用)使用场景案例

1.排行榜系统(游戏积分榜)

java 复制代码
@Service
public class GameRankingService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String RANKING_KEY = "game:ranking";
    
    // 更新玩家分数
    public void updatePlayerScore(String playerId, double score) {
        redisTemplate.opsForZSet().add(RANKING_KEY, playerId, score);
    }
    
    // 获取玩家排名(从高到低)
    public Long getPlayerRank(String playerId) {
        // ZREVRANK 获取从高到低的排名
        return redisTemplate.opsForZSet().reverseRank(RANKING_KEY, playerId);
    }
    
    // 获取排行榜前N名
    public Set<ZSetOperations.TypedTuple<Object>> getTopPlayers(int topN) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, topN - 1);
    }
    
    // 获取玩家分数
    public Double getPlayerScore(String playerId) {
        return redisTemplate.opsForZSet().score(RANKING_KEY, playerId);
    }
}

2.延迟队列

java 复制代码
@Service
public class DelayTaskService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String DELAY_QUEUE_KEY = "delay:tasks";
    
    // 添加延时任务
    public void addDelayTask(String taskId, long delaySeconds) {
        double executeTime = System.currentTimeMillis() + delaySeconds * 1000;
        redisTemplate.opsForZSet().add(DELAY_QUEUE_KEY, taskId, executeTime);
    }
    
    // 扫描并执行到期任务
    public void executeExpiredTasks() {
        long currentTime = System.currentTimeMillis();
        
        // 获取所有已到期的任务
        Set<ZSetOperations.TypedTuple<Object>> expiredTasks = 
            redisTemplate.opsForZSet().rangeByScoreWithScores(DELAY_QUEUE_KEY, 0, currentTime);
        
        for (ZSetOperations.TypedTuple<Object> task : expiredTasks) {
            String taskId = (String) task.getValue();
            
            // 执行任务逻辑
            processTask(taskId);
            
            // 从队列中移除已处理的任务
            redisTemplate.opsForZSet().remove(DELAY_QUEUE_KEY, taskId);
        }
    }
    
    private void processTask(String taskId) {
        // 具体的任务处理逻辑
        System.out.println("Processing task: " + taskId + " at " + System.currentTimeMillis());
    }
}

3.热点数据统计

java 复制代码
@Service
public class HotDataService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String HOT_ARTICLES_KEY = "hot:articles";
    
    // 增加文章阅读量
    public void incrementArticleView(Long articleId) {
        redisTemplate.opsForZSet().incrementScore(HOT_ARTICLES_KEY, 
            String.valueOf(articleId), 1);
    }
    
    // 获取热门文章TopN
    public Set<ZSetOperations.TypedTuple<Object>> getHotArticles(int topN) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(HOT_ARTICLES_KEY, 0, topN - 1);
    }
    
    // 获取文章排名
    public Long getArticleRank(Long articleId) {
        return redisTemplate.opsForZSet().reverseRank(HOT_ARTICLES_KEY, 
            String.valueOf(articleId));
    }
}

4.时间轴实现

java 复制代码
@Service
public class TimelineService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 添加动态到用户时间轴
    public void addToTimeline(String userId, String postId, long timestamp) {
        String timelineKey = "timeline:" + userId;
        redisTemplate.opsForZSet().add(timelineKey, postId, timestamp);
        
        // 限制时间轴长度,只保留最近1000条
        redisTemplate.opsForZSet().removeRange(timelineKey, 0, -1001);
    }
    
    // 获取用户时间轴
    public Set<Object> getTimeline(String userId, int page, int size) {
        String timelineKey = "timeline:" + userId;
        long start = (page - 1) * size;
        long end = start + size - 1;
        
        // 按时间倒序排列
        return redisTemplate.opsForZSet().reverseRange(timelineKey, start, end);
    }
    
    // 删除时间轴中的某条动态
    public void removeFromTimeline(String userId, String postId) {
        String timelineKey = "timeline:" + userId;
        redisTemplate.opsForZSet().remove(timelineKey, postId);
    }
}

5.社交列表实现

复制代码
@Service
public class SocialFollowService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 关注用户
     */
    public void followUser(String followerId, String followeeId) {
        String followKey = "user:" + followerId + ":follows";
        double timestamp = System.currentTimeMillis();
        redisTemplate.opsForZSet().add(followKey, followeeId, timestamp);
    }
    
    /**
     * 取消关注
     */
    public void unfollowUser(String followerId, String followeeId) {
        String followKey = "user:" + followerId + ":follows";
        redisTemplate.opsForZSet().remove(followKey, followeeId);
    }
    
    /**
     * 获取最近关注的用户(按时间倒序)
     */
    public Set<Object> getRecentFollows(String userId, int limit) {
        String followKey = "user:" + userId + ":follows";
        return redisTemplate.opsForZSet().reverseRange(followKey, 0, limit - 1);
    }
    
    /**
     * 获取关注时间
     */
    public Double getFollowTime(String followerId, String followeeId) {
        String followKey = "user:" + followerId + ":follows";
        return redisTemplate.opsForZSet().score(followKey, followeeId);
    }
}

6.滑动窗口实现(限流)

复制代码
@Service
public class SlidingWindowRateLimitService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 记录请求并清理过期数据
     */
    public boolean allowRequest(String clientId, int windowSeconds, int maxRequests) {
        String key = "rate:limit:" + clientId;
        long currentTime = System.currentTimeMillis();
        long windowStartTime = currentTime - windowSeconds * 1000L;
        
        // 记录当前请求
        redisTemplate.opsForZSet().add(key, String.valueOf(currentTime), currentTime);
        
        // 清理窗口期之前的请求
        redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStartTime);
        
        // 获取当前窗口内的请求数量
        Long requestCount = redisTemplate.opsForZSet().zCard(key);
        
        // 设置过期时间
        redisTemplate.expire(key, windowSeconds, TimeUnit.SECONDS);
        
        return requestCount != null && requestCount <= maxRequests;
    }
    
    /**
     * 获取当前请求数量
     */
    public Long getCurrentRequestCount(String clientId) {
        String key = "rate:limit:" + clientId;
        return redisTemplate.opsForZSet().zCard(key);
    }
}

7.地理位置搜索

复制代码
@Service
public class GeoLocationService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String USER_LOCATIONS_KEY = "user:locations";
    
    /**
     * 添加用户位置
     * 将经纬度合并为一个唯一的分数
     */
    public void addUserLocation(String userId, double latitude, double longitude) {
        // 将经纬度编码为一个唯一的double值
        double locationScore = encodeLocation(latitude, longitude);
        redisTemplate.opsForZSet().add(USER_LOCATIONS_KEY, userId, locationScore);
    }
    
    /**
     * 编码地理位置(简单实现)
     */
    private double encodeLocation(double latitude, double longitude) {
        // 将经纬度转换为固定格式的数字
        // 例如:纬度40.7128,经度-74.0060 -> 407128740060
        return latitude * 1000000 + longitude;
    }
    
    /**
     * 查找附近用户(简化版本)
     */
    public Set<Object> findNearbyUsers(double centerLat, double centerLng, double radius) {
        double minScore = encodeLocation(centerLat - radius, centerLng - radius);
        double maxScore = encodeLocation(centerLat + radius, centerLng + radius);
        
        return redisTemplate.opsForZSet().rangeByScore(USER_LOCATIONS_KEY, minScore, maxScore);
    }
    
    /**
     * 获取用户位置
     */
    public Double getUserLocation(String userId) {
        return redisTemplate.opsForZSet().score(USER_LOCATIONS_KEY, userId);
    }
}
相关推荐
消失的旧时光-19433 小时前
Flutter 工程中 mixin 的正确打开方式:5 种高质量设计范式 + mixin vs 继承 vs 组合 + 为什么它比 BasePage 更优雅
前端·flutter·架构
乐吾乐科技3 小时前
乐吾乐3D可视化2025重大更新与2026升级计划
前端·3d·信息可视化·编辑器·数据可视化
C_心欲无痕3 小时前
html - 使用视频做天气卡片背景
前端·html·音视频
WoY20203 小时前
conda修改镜像源遇到的问题:defaults(默认镜像源)清不干净导致创建环境失败
linux·python·conda
渡我白衣4 小时前
计算机组成原理(11):加法器
python·机器学习·numpy·pandas·matplotlib·计组·数电
毕设十刻4 小时前
基于Vue的养老服务平台85123(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
青衫折扇4 小时前
执行 npm 安装命令时,包被装到了 C 盘用户目录下,而非项目根目录
前端·npm·node.js
蜀中孤鹰4 小时前
从秒级到毫秒级:一次Redis限流脚本的深度优化实战
redis·spring cloud·lua
XiaoYu20024 小时前
第2章 Nest.js入门
前端·ai编程·nestjs
龙腾AI白云4 小时前
深度学习—卷积神经网络(3)
人工智能·python