【Redis】BitMap数据类型与用户签到功能的实现

目录

一、BitMap

1、概念

2、命令

1.SETBIT

2.GETBIT

3.BITCOUNT

4.BITFIELD

5.BITFIELD RO

6.BITOP

7.BITPOS

二、用户签到

1、思路

2、代码实现

三、当前时间的连续签到天数

1、思路

2、代码实现


一、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 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;
    }

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