目录
一、BitMap
1、概念
Redis中通过String类型实现的一种数据类型,因此存储上限是512M,转换为bit则是2^32个比特位,每一位存储0或1
2、命令
1.SETBIT
向指定key的指定位置中存入0或1
2.GETBIT
获取指定key指定位置的值
3.BITCOUNT
计算指定key中值为1的bit位数量
4.BITFIELD
查询、修改、自增指定key指定位置的值
5.BITFIELD RO
获取指定key中的bit数组,以十进制形式返回
6.BITOP
将多个指定key的结果做位运算
7.BITPOS
查询 bit数组中指定范围内第一个0或1出现的位置
二、用户签到
1、思路
一个月最多有31天,而bitMap有31位,我们可以将当前签到用户的id与当前时间年份+月份作为key,以BitMap为数据结构进行存储用户该月是否签到每一位表示一天,0与1表示是否签到,当用户点击签到请求时,服务器获取当前的时间与当前签到用户的id,以id+当前年月时间作为key,将当前的日作为下标,在BitMap中指定下标位存储1,比如当前签到用户是张三id=1,则key= “sign:1:2020-01”作为key,今天是1月11,则将这个key的第11位的也就是10下标的值修改为1即可表示签到
2、代码实现
void test() {
// 1.获取当前用户id
Long userId = 1L;
// 2.获取当前时间
LocalDateTime now = LocalDateTime.now();
// 2.1 获取年月
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
// 2.2 获取日
int day = now.getDayOfMonth();
// 3.存入redis
// 3.1 构造key
String key = "sign:" + userId + keySuffix;
// 3.2 存入
stringRedisTemplate.opsForValue().setBit(key,day - 1,true);
}
三、当前时间的连续签到天数
1、思路
当前时间的连续签到天数一定是从现在开始往前数,直到遇到没有签到的那天则结束计算,我们只需要获取到当前用户当前时间对应的bitMap中的每一个比特位,然后从后往前数1当数到0时则停止,最后返回数量即可,我们可以通过BITFIELD RO命令以十进制形式获取到数据,然后按位与1后,如果结果是1则计算变量++后无符合右移1位继续按位与1,直到按位与1等于0时停止。
比如 5 他的二进制是101,从后往前计算他的1的连续个数,101先进行101&1 = 1则计数器+1为1,此时101>>>1 变为10,此时10&1 = 0结束循环计数器值为1,说明从后往前连续的1只有1个
2、代码实现
Integer test() {
// 1.获取用户id
Long userId = 1L;
// 2.获取当前时间
LocalDateTime now = LocalDateTime.now();
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
int day = now.getDayOfMonth();
// 3.获取对应的签到数值
String key = "sign:" + userId + keySuffix;
List<Long> result = stringRedisTemplate.opsForValue().bitField(
key,
BitFieldSubCommands.create()
.get(BitFieldSubCommands.BitFieldType.unsigned(day)).valueAt(0)
);
if (result == null || result.isEmpty()) {
return null;
}
// 4.开始计数
Long num = result.get(0);
if (num == null || num == 0) return null;
int count = 0;
while (true) {
if ((num & 1) == 1) {
count++;
} else {
break;
}
num >>>= 1;
}
// 5.返回
return count;
}