前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis使用场景总结

Redis使用场景总结

作者头像
九转成圣
发布2024-04-10 18:19:50
620
发布2024-04-10 18:19:50
举报
文章被收录于专栏:csdncsdn

Redis使用场景

缓存(减少数据库压力)

  1. 缓存热点数据
  2. 缓存一些计算结果

数据共享

  1. 分布式锁
  2. 分布式计数器
  3. 分布式session

redis自身的特性

sortedset的排行榜

代码语言:javascript
复制
public class LeaderboardService {
    private final RedisTemplate<String, String> redisTemplate;

    public LeaderboardService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 添加玩家到排行榜
    public void addPlayerToLeaderboard(String player, double score) {
        redisTemplate.opsForZSet().add("leaderboard", player, score);
    }

    // 获取排行榜中前 N 名玩家 /rɪˈvɜːs/
    public Set<ZSetOperations.TypedTuple<String>> getLeaderboard(int topN) {
        return redisTemplate.opsForZSet().reverseRangeWithScores("leaderboard", 0, topN - 1);
    }

    // 更新玩家在排行榜中的分数
    public void updatePlayerScore(String player, double score) {
        redisTemplate.opsForZSet().incrementScore("leaderboard", player, score);
    }

    // 从排行榜中移除玩家
    public void removePlayerFromLeaderboard(String player) {
        redisTemplate.opsForZSet().remove("leaderboard", player);
    }
}

利用set的pop()和randomMembers抽奖

代码语言:javascript
复制
/**
 * 一等奖1个,二等奖2个,三等奖3个,参与奖100个
 */
public class LotteryService {
    private final RedisTemplate<String, String> redisTemplate;
    private final JdbcTemplate jdbcTemplate;
    private static final String SPOP_USER_SETS = "pop:user:set";

    public LotteryService(JdbcTemplate jdbcTemplate, RedisTemplate<String, String> redisTemplate) {
        this.jdbcTemplate = jdbcTemplate;
        this.redisTemplate = redisTemplate;
    }

    public void initUserSet(String prize) {
        String sql = "select id from user";
        List<Map<String, Object>> userIds = jdbcTemplate.queryForList(sql);
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        String[] ids = userIds.stream().map(item -> String.valueOf(item.get("id").toString())).toArray(String[]::new);
        ops.add(SPOP_USER_SETS, ids);
    }

    public void drawAllPrize() {
        List<String> firstPrize = drawPrize(1);
        System.out.println("一等奖:" + firstPrize.get(0));
        List<String> secondPrize = drawPrize(2);
        System.out.println("二等奖:" + String.join(",", secondPrize));
        List<String> thirdPrize = drawPrize(3);
        System.out.println("三等奖:" + String.join(",", thirdPrize));
        List<String> participationPrize = drawPrize(100);
        System.out.println("参与奖:" + String.join(",", participationPrize));
    }

    /**
     * 一个人最多获取一次奖品
     * @param count
     * @return
     */
    public List<String> drawPrize(int count) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        // Remove and return count random members from set at key.
        return ops.pop("prize_pool", count);
    }

    /**
     * draw 抽取
     * 允许一个人多次抽取奖品
     * @param count
     * @return
     */
    public List<String> drawPrize4duplicate(int count) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        // Get count random elements from set at key.
        return ops.randomMembers("prize_pool", count);
    }

}

统计

基于String的统计

无法去重,准确

代码语言:javascript
复制
public class Stats4String {
    private RedisTemplate<String, String> redisTemplate;

    public Stats4String(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 比如点赞/收藏
    public void incrementCount(String key) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.increment(key);
    }

    // 比如取消点赞/取消收藏
    public void decrementCount(String key) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.decrement(key);
    }

    // 获取统计数量
    public Long getCount(String key) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String countStr = ops.get(key);

        if (countStr != null) {
            return Long.parseLong(countStr);
        } else {
            return 0L;
        }
    }

    // 清空统计数据
    public void clearCount(String key) {
        redisTemplate.delete(key);
    }
}
基于HyperLogLog的统计

去重,不可减,不准确,节省内存

代码语言:javascript
复制
public class Stats4HyperLogLog {
    private RedisTemplate<String, String> redisTemplate;

    public Stats4HyperLogLog(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 添加元素到 HyperLogLog
    public void addElement(String key, String... elements) {
        HyperLogLogOperations<String, String> ops = redisTemplate.opsForHyperLogLog();
        ops.add(key, elements);
    }

    // 获取 HyperLogLog 的基数估计值
    public long getApproximateCount(String key) {
        HyperLogLogOperations<String, String> ops = redisTemplate.opsForHyperLogLog();
        return ops.size(key);
    }

    // 合并多个 HyperLogLog
    public void mergeHyperLogLogs(String destinationKey, String... sourceKeys) {
        HyperLogLogOperations<String, String> ops = redisTemplate.opsForHyperLogLog();
        ops.union(destinationKey, sourceKeys);
    }

    // 清空 HyperLogLog
    public void clearHyperLogLog(String key) {
        redisTemplate.delete(key);
    }
}
基于Set的统计
代码语言:javascript
复制
public class SetStats4Set {
    private final RedisTemplate<String, String> redisTemplate;

    public SetStats4Set(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 例如点赞
    public void add(String key, String... elements) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        ops.add(key, elements);
    }

    // 例如取消点赞
    public void remove(String key, Object... elements) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        ops.remove(key, elements);
    }

    // 例如点赞数
    public long getDistinctCount(String key) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        Long size = ops.size(key);
        return size != null ? size : 0L;
    }

    // 例如点赞的人
    public Set<String> members(String key) {
        SetOperations<String, String> ops = redisTemplate.opsForSet();
        return ops.members(key);
    }

    // 清空集合
    public void clearSet(String key) {
        redisTemplate.delete(key);
    }
}

基于bitmap的统计

点赞数,第一个点赞的人,所有点赞的人

代码语言:javascript
复制
@Component
public class BitmapStatsService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    // 例如点赞
    public void add(String key, int userId) {
        setBit(key, userId, true);
    }

    // 例如取消点赞
    public void remove(String key, int userId) {
        setBit(key, userId, false);
    }

    // 例如点赞数
    public long getDistinctCount(String key) {
        return bitCount(key);
    }

    // 例如点赞的人
    public List<Integer> members(String key) {
        String value = redisTemplate.opsForValue().get(key);
        List<Integer> list = new ArrayList<>();
        for (byte b : value.getBytes()) {
            for (int i = 7; i >= 0; i--) {
                list.add((b >> i) & 1);
            }
        }
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) == 1) {
                result.add(i);
            }
        }
        return result;
    }


    // 设置指定位置的位值
    public void setBit(String key, long offset, boolean value) {
        redisTemplate.opsForValue().setBit(key, offset, value);
    }

    // 获取指定位置的位值
    public Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    // 统计指定范围内的位值为 true 的个数
    public Long bitCount(String key) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitCount(key.getBytes()));
    }

    public Long bitCount(String key, long start, long end) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitCount(key.getBytes(), start, end));
    }

    // 首签时间
    public Long bitPos(String key, boolean bit) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitPos(key.getBytes(), bit));
    }

    public Long bitPos(String key, boolean bit, Long start, Long end) {
        Range<Long> range = Range.closed(start, end);
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitPos(key.getBytes(), bit, range));
    }

    // 连续签到/累计签到
    public Long bitOp(RedisStringCommands.BitOperation op, String destination, String... keys) {
        byte[][] keyBytes = new byte[keys.length][];
        for (int i = 0; i < keys.length; i++) {
            keyBytes[i] = keys[i].getBytes();
        }
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.bitOp(op, destination.getBytes(), keyBytes));
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Redis使用场景
  • 缓存(减少数据库压力)
  • 数据共享
  • redis自身的特性
    • sortedset的排行榜
      • 利用set的pop()和randomMembers抽奖
        • 统计
          • 基于String的统计
          • 基于HyperLogLog的统计
          • 基于Set的统计
      • 基于bitmap的统计
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档