SpringCloud天机学堂:Redis BitMap 实现用户签到功能详解

SpringCloud天机学堂:Redis BitMap 实现用户签到功能详解


1.、Redis BitMap 概述

Redis BitMap 是一种基于字符串类型的特殊数据结构,用于高效处理大量布尔值(0或1)。它在需要处理大规模数据时特别有用,如用户活动跟踪、权限管理和大规模数据的快速计数等场景。

BitMap 的核心优势在于其空间效率和操作速度。每个比特只占用一位空间,因此在处理大规模布尔值数据时非常节省内存。例如,存储 1 亿个布尔值,BitMap 只需要约 12.5MB 的内存。

2、 BitMap 的基础操作
SETBIT

SETBIT key offset value 用于设置 key 对应的位图中某个偏移量的值。

示例:

SETBIT user_activity:2024-08-19 5 1
GETBIT

GETBIT key offset 用于获取 key 对应的位图中某个偏移量的值。

示例:

GETBIT user_activity:2024-08-19 5
BITCOUNT

BITCOUNT key [start end] 用于计算位图中被设置为 1 的比特位的数量。

示例:

BITCOUNT user_activity:2024-08-19
BITFIELD

BITFIELD key [GET type offset] 用于在一次调用中对多个位进行操作。

示例:

BITFIELD user_activity:2024-08 GET u31 0
3、实现签到功能
接口设计

签到接口设计如下:

  • 请求方式:POST

  • 请求路径:/sign-records

  • 请求参数:无

  • 返回值:

    {
      "signDays": 10, // 连续签到天数
      "points": 14 // 今日签到获取的积分
    }
    
实现步骤
  1. 生成 BitMap 的 key
    格式:sign:uid:xxx:yyyyMM

  2. 获取当前日期,计算要设置的 bit 位 offset

  3. 使用 SETBIT 命令设置签到

  4. 统计连续签到天数

    • 使用 BITFIELD 获取本月至今的签到记录
    • 从后向前遍历,直到遇到第一个未签到日
  5. 计算获得的积分

    • 基础积分 1 分
    • 连续签到奖励:7天 10分,14天 20分,28天 40分
  6. 保存积分明细(TODO)

  7. 封装返回结果

核心代码实现
@Override
public SignResultVO addSignRecords() {
    // 1. 签到
    Long userId = UserContext.getUser();
    LocalDate now = LocalDate.now();
    String key = RedisConstants.SIGN_RECORD_KEY_PREFIX 
                 + userId + now.format(DateUtils.SIGN_DATE_SUFFIX_FORMATTER);
    int offset = now.getDayOfMonth() - 1;
    
    Boolean exists = redisTemplate.opsForValue().setBit(key, offset, true);
    if (BooleanUtils.isTrue(exists)) {
        throw new BizIllegalException("不允许重复签到!");
    }

    // 2. 计算连续签到天数
    int signDays = countSignDays(key, now.getDayOfMonth());
    
    // 3. 计算签到得分
    int rewardPoints = calculateRewardPoints(signDays);

    // 4. 保存积分明细记录(TODO)

    // 5. 封装返回
    SignResultVO vo = new SignResultVO();
    vo.setSignDays(signDays);
    vo.setRewardPoints(rewardPoints);
    return vo;
}

private int countSignDays(String key, int len) {
    List<Long> result = redisTemplate.opsForValue()
        .bitField(key, BitFieldSubCommands.create()
                  .get(BitFieldSubCommands.BitFieldType.unsigned(len)).valueAt(0));
    if (CollUtils.isEmpty(result)) {
        return 0;
    }
    int num = result.get(0).intValue();
    int count = 0;
    while ((num & 1) == 1) {
        count++;
        num >>>= 1;
    }
    return count;  
}
4. 在 Java 中使用 BitMap

在 Java 中,可以通过 Jedis 或 Spring Data Redis 等 Redis 客户端库来使用 BitMap 功能。以下是使用 Spring Data Redis 的示例:

@Autowired
private StringRedisTemplate redisTemplate;

public void signIn(Long userId, LocalDate date) {
    String key = "user:sign:" + userId + ":" + date.format(DateTimeFormatter.ofPattern("yyyyMM"));
    int dayOfMonth = date.getDayOfMonth();
    redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
}

public boolean checkSignIn(Long userId, LocalDate date) {
    String key = "user:sign:" + userId + ":" + date.format(DateTimeFormatter.ofPattern("yyyyMM"));
    int dayOfMonth = date.getDayOfMonth();
    return redisTemplate.opsForValue().getBit(key, dayOfMonth - 1);
}
5、 总结

Redis BitMap 是一种高效、紧凑的位操作工具,特别适合处理大规模布尔值数据的场景。通过简单的命令和操作,可以实现快速的存储、查询和统计功能。在实现用户签到功能时,BitMap 展现了其在空间效率和操作速度方面的优势,能够有效处理大量用户的签到记录,并支持快速的连续签到统计。

结合 Java 和 Spring Data Redis,我们可以轻松地将 BitMap 集成到应用中,满足各种复杂的业务需求,如用户签到、活跃度统计等。通过深入理解 BitMap 的工作原理和使用方法,开发者可以在处理大规模数据时选择更加高效的解决方案。

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小林学习编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值