Redis实战案例26-签到功能

1. BitMap

Redis实战案例26-签到功能_第1张图片

假如用户数量为一千万,平均每人每年签到次数为 10 次,则这张表一年的数据量为 1 亿条;
而每签到一次需要使用(8 + 8 + 1 + 1 + 3 + 1)共 22 字节的内存,一个月则最多需要 600 多字节,如果是一千万的用户,则数据量非常庞大;

Redis实战案例26-签到功能_第2张图片
这样统计一个月的字节大小为4字节,大大缩小了内存使用;

Redis实战案例26-签到功能_第3张图片
Redis实战案例26-签到功能_第4张图片

2. 签到功能实现

Redis实战案例26-签到功能_第5张图片

/**
 * BitMap实现用户签到
 * @return
 */
@Override
public Result sign() {
    //1. 获取当前登录用户
    Long userId = UserHolder.getUser().getId();
    //2. 获取日期
    LocalDateTime now = LocalDateTime.now();
    //3. 拼接key
    String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + format;
    //4. 获取今天是本月的第几天
    int dayOfMonth = now.getDayOfMonth();
    //5. 写入Redis SETBIT key offset 1
    stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
    return Result.ok();
}

Redis实战案例26-签到功能_第6张图片

3. 签到统计

Redis实战案例26-签到功能_第7张图片
Redis实战案例26-签到功能_第8张图片

/**
 * 统计签到次数
 * @return
 */
@Override
public Result signCount() {
    //1. 获取当前登录用户
    Long userId = UserHolder.getUser().getId();
    //2. 获取日期
    LocalDateTime now = LocalDateTime.now();
    //3. 拼接key
    String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + format;
    //4. 获取今天是本月的第几天
    int dayOfMonth = now.getDayOfMonth();
    //5. 获取本月截至今天为止的所有签到记录,返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0
    List<Long> result = stringRedisTemplate.opsForValue().bitField(
            key,
            BitFieldSubCommands.create()
                    .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
    );
    if(result == null || result.isEmpty()) {
        // 没有任何结果
        return Result.ok(0);
    }
    Long num = result.get(0);
    if(num == null || num == 0) {
        return Result.ok(0);
    }
    //6. 循环遍历
    int count = 0;
    while(true) {
        // 让这个数字与1做与运算,得到数字的最后一个bit位
        // 判断这个bit位是否为0
        if((num & 1) == 0) {
            // 如果为0,说明未签到,结束
            break;
        }else {
            // 如果不为0,说明已签到,计数器+1
            count++;
        }
        // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位(右移一位并赋值)
        num >>>= 1;
    }
    return Result.ok(count);
}

你可能感兴趣的:(Redis,redis,数据库,缓存)