Spring-Boot-Redis-BitMap
在各个项目中,我们都可能需要用到签到和 统计功能。签到后会给用户一些礼品以此来吸引用户持续在该平台进行活跃。
签到功能,我们可以通过Redis中的 BitMap功能来实现
Redis BitMap 基本用法
⛅BitMap 基本语法、指令
签到功能我们可以使用MySQL来完成,比如下表:
CREATE TABLEtb sign (
`id` bigint(20) unsigned NOT NULL AUTO INCREMENTCOMMENT '主键',
`user_id` bigint(20) unsigned NOT NULL COMMENT '用户id',
'year' year(4) NOT NULL COMMENT '签到的年',
'month' tinyint(2) NOT NULL COMMENT '签到的月',
'date' date NOT NULL COMMENT '签到的日期',
'is_backup' tinyint(1) unsigned DEFAULT NULL COMMENT '是否补签',
PRIMARY KEY ('id') USING BTREE
) ENGINE-InnoDB DEFAULT CHARSET=utf8mb4 ROW FORMAT=COMPACT
用户一次签到,就是一条记录,假如有1000万用户,平均每人每年签到次数为10次,则这张表一年的数据量为 1亿条
每签到一次需要使用(8 + 8 + 1 + 1 + 3 + 1)共22 字节的内存,一个月则最多需要600多字节
这样的坏处,占用内存太大了,极大的消耗内存空间!
我们可以根据 Redis中 提供的 BitMap 位图功能来实现,每次签到与未签到用0 或1 来标识 ,一次存31个数字,只用了2字节 这样我们就用极小的空间实现了签到功能
BitMap 的操作指令:
- SETBIT:向指定位置(offset)存入一个0或1
- GETBIT :获取指定位置(offset)的bit值
- BITCOUNT :统计BitMap中值为1的bit位的数量
- BITFIELD :操作(查询、修改、自增)BitMap中bit数组中的指定位置(offset)的值
- BITFIELD_RO :获取BitMap中bit数组,并以十进制形式返回
- BITOP :将多个BitMap的结果做位运算(与 、或、异或)
- BITPOS :查找bit数组中指定范围内第一个0或1出现的位置
⚡使用 BitMap 完成功能实现
服务器Redis版本采用 6.2
进入redis查询 SETBIT 命令
help SETBIT
新增key 进行存储
SETBIT mb1 0 1
SETBIT mb1 1 1
SETBIT mb1 2 1
SETBIT mb1 4 1
SETBIT mb1 5 1
查询 GETBIT 命令
help GETBIT
查看指定坐标的签到状态
GETBIT mb1 2
查询 BITFIELD
help BITFIELD
无符号查询
BITFIELD bm1 get u2 0
BITPOS 查询1 和 0 第一次出现的坐标
BITPOS bm1 0
BITPOS bm1 1
SpringBoot 整合 Redis 实现签到 功能
☁️需求介绍
采用BitMap实现签到功能
- 实现签到接口,将当前用户当天签到信息保存到Redis中
思路分析:
我们可以把 年和月 作为BitMap的key,然后保存到一个BitMap中,每次签到就到对应的位上把数字从0 变为1,只要是1,就代表是这一天签到了,反之咋没有签到。
实现签到接口,将当前用户当天签到信息保存至Redis中 图片
提示:因为BitMap 底层是基于String数据结构,因此其操作都封装在字符串操作中了。
图片
⚡核心源码
UserController
@PostMapping("sign")
public Result sign() {
return userService.sign();
}
UserServiceImpl
public Result sign() {
//1. 获取登录用户
Long userId = UserHolder.getUser().getId();
//2. 获取日期
LocalDateTime now = LocalDateTime.now();
//3. 拼接key
String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
String key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
//4. 获取今天是本月的第几天
int dayOfMonth = now.getDayOfMonth();
//5. 写入redis setbit key offset 1
stringRedisTemplate.opsForValue().setBit(key, dayOfMonth -1, true);
return Result.ok();
}
接口进行测试
ApiFox进行测试
图片
查看Redis 数据 图片