【遇见青山】基于Redis BitMap实现签到功能案例
1.BitMap
我们按月来统计用户签到信息,签到记录为1,未签到则记录为0
把每一个bit位对应当月的每一天,形成了映射关系。用0和1标示业务状态,这种思路就称为位图(BitMap)。
Redis中是利用string类型数据结构实现BitMap,因此最大上限是512M,转换为bit则是2^32个bit位。
BitMap常用命令:
2.签到代码实现
首先,基于BitMap实现进行当日的签到:
/** * 签到 * * @return Result */ @Override public Result sign() { // 获取当前登录用户 Long userId = UserHolder.getUser().getId(); // 获取日期 LocalDateTime now = LocalDateTime.now(); String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM")); String key = USER_SIGN_KEY + userId + keySuffix; // 获取今天是本月第几天 int dayOfMonth = now.getDayOfMonth(); // 写入bitmap,进行签到 stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true); return Result.ok(); }
今天是当月的第15天,则在BitMap的第15位将置为1:
3.连续签到天数
lowbit运算,判断连续签到天数:
很简单代码实现:
/** * 计算连续签到天数 * * @return Result */ @Override public Result signCount() { // 获取当前登录用户 Long userId = UserHolder.getUser().getId(); // 获取日期 LocalDateTime now = LocalDateTime.now(); String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM")); String key = USER_SIGN_KEY + userId + keySuffix; // 获取今天是本月第几天 int dayOfMonth = now.getDayOfMonth(); // 获取本月到今天的签到记录 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); } // 连续签到天数 int count = 0; // 循环lowbit运算 while ((num & 1) != 0) { count++; num >>>= 1; } return Result.ok(count); }
下一篇:
使用Navicat生成MySQL测试数据