【遇见青山】基于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测试数据
