当前位置: 首页 > news >正文

基于Redis实现-用户签到

基于Redis实现-用户签到

这个功能将使用到Redis中的BitMap来实现。

我们按照月来统计用户签到信息,签到记录为1,未签到则记录为0

在这里插入图片描述

把每一个bit位对应当月的每一天,形成了映射关系。用0和1标示业务状态,这种思路称为位图(BitMap)。

Redis中是利用String类型数据结构实现BitMap,因此最大上限是512M,转化为bit则是2的32次方个bit位。相比于使用数据库字段来存储,内存使用大大减小。

1.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出现的位置

语法演示:

1. SETBIT - 用户签到
# 用户ID 1001 在第5天签到(offset从0开始)
SETBIT user:sign:1001 4 1# 用户ID 1001 在第10天签到
SETBIT user:sign:1001 9 1
#-------------------------------------------------------------------------------------------
#2. GETBIT - 检查某天是否签到
# 检查用户ID 1001 第5天是否签到
GETBIT user:sign:1001 4
# 返回1表示已签到# 检查用户ID 1001 第6天是否签到
GETBIT user:sign:1001 5
# 返回0表示未签到
#-------------------------------------------------------------------------------------------
#3. BITCOUNT - 统计签到总天数
# 统计用户ID 1001 本月签到总天数
BITCOUNT user:sign:1001
# 返回签到的总天数
#-------------------------------------------------------------------------------------------
#4. BITFIELD - 批量操作签到数据
# 获取用户ID 1001 前5天的签到情况(以无符号5位整数形式返回)
BITFIELD user:sign:1001 GET u5 0# 同时设置多个签到日
BITFIELD user:sign:1001 SET u1 15 1 SET u1 16 1
#-------------------------------------------------------------------------------------------
#5. BITFIELD_RO - 只读方式获取签到数据
# 安全地获取用户ID 1001 前10天的签到情况
BITFIELD_RO user:sign:1001 GET u10 0
#-------------------------------------------------------------------------------------------
#6. BITOP - 多用户签到情况统计
# 创建两个用户的签到数据
SETBIT user:sign:1001 0 1
SETBIT user:sign:1001 1 1
SETBIT user:sign:1002 0 1# 统计哪些天数两个用户都签到了(按位与操作)
BITOP AND both_sign user:sign:1001 user:sign:1002# 查看结果
GETBIT both_sign 0  # 返回1,表示第1天都签到了
GETBIT both_sign 1  # 返回0,表示第2天不是都签到了
#-------------------------------------------------------------------------------------------
#7. BITPOS - 查找连续签到
# 查找用户ID 1001 第一次签到的位置(从第0位开始查找值为1的位)
BITPOS user:sign:1001 1# 查找用户ID 1001 第一次未签到的位置
BITPOS user:sign:1001 0
#-------------------------------------------------------------------------------------------
#完整签到系统示例
# 用户1001连续7天的签到情况(1已签,0未签)
SETBIT user:sign:1001 0 1  # 第1天
SETBIT user:sign:1001 1 1  # 第2天
SETBIT user:sign:1001 2 0  # 第3天未签
SETBIT user:sign:1001 3 1  # 第4天
SETBIT user:sign:1001 4 1  # 第5天
SETBIT user:sign:1001 5 0  # 第6天未签
SETBIT user:sign:1001 6 1  # 第7天# 查询签到情况
BITCOUNT user:sign:1001  # 返回5(共签到了5天)
BITPOS user:sign:1001 0  # 返回2(第一个未签到的位置)

2.使用Java实现简单的用户签到

注意:因为BitMap底层是基于String数据结构,因此其操作都封装在字符串操作中。

在这里插入图片描述

1.实现用户签到

//在ServiceImpl@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result sign() {//1.获取当前用户Long UserId = UserHolder.getUser().getId();//2.获取当前日期LocalDateTime now = LocalDateTime.now();//3.拼接keyString KeySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));String key="sign:"+UserId+":"+KeySuffix;//4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();//5.写入redisstringRedisTemplate.opsForValue().setBit(key,dayOfMonth-1,true);return Result.ok();}

2.Java实现统计连续签到

1.什么是;连续签到天数?

从最后一次签到开始向前统计,直到遇到第一次未签到为止,计算总的签到次数,就是连续的签到天数。

2.如何得到本月到今天为止的所有签到数据?

BITFIELD key GET u[dayOfMonth] 0

3.如何从后向前遍历每个bit位?

与1做与运算,就能得到最后一个bit位。

随后右移一位,下一个bit为就成为了最后一个bit位。

//在ServiceImpl@Autowiredprivate StringRedisTemplate stringRedisTemplate;
@Override
public Result signCount() {// 1.获取当前登录用户IDLong UserId = UserHolder.getUser().getId();// 2.获取当前日期时间(带时区)LocalDateTime now = LocalDateTime.now();// 3.拼接Redis键:sign:用户ID:年月(例如:sign:1001:202310)String KeySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));String key = "sign:" + UserId + ":" + KeySuffix;// 4.获取今天是本月的第几天(1-31)int dayOfMonth = now.getDayOfMonth();// 5.使用BITFIELD命令获取本月签到数据的位图(返回无符号整数)// 格式:BITFIELD key GET u<dayOfMonth> 0// 表示从偏移量0开始,获取dayOfMonth长度的无符号整数List<Long> longs = stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));// 5.1 处理空结果情况if (longs == null || longs.isEmpty()) {return Result.ok(0);  // 无签到记录返回0}// 5.2 获取位图转换后的十进制数值Long num = longs.get(0);if (num == null || num == 0) {return Result.ok(0);  // 数值为0表示无签到}// 6.通过位运算计算连续签到天数int count = 0;while (true) {// 6.1 检查最低位是否为1(与1做按位与运算)// 结果为0表示未签到,1表示已签到if ((num & 1) == 0) {break;  // 遇到未签到日终止循环} else {count++;  // 签到日计数器+1}// 6.2 无符号右移一位(相当于删除已检查的最低位)// 例如:1011(11) >>> 1 = 0101(5)num >>>= 1;}// 7.返回连续签到天数return Result.ok(count);
}

关于BITFIELD参数使用解释

  1. key

    • 作用:Redis 中存储 BitMap 的键名

    • 示例"sign:1001:202310"(用户1001在2023年10月的签到数据)

    • 底层命令BITFIELD key [GET type offset]

    • 说明:指定要操作的 BitMap 键

  2. BitFieldSubCommands.create()

    • 作用:创建 BITFIELD 命令的子命令构建器

    • 说明

      • Spring Data Redis 的封装方法,用于构建复杂的 BITFIELD 操作
      • 对应 Redis 原生命令中的 [GET/SET/INCR ...] 部分
  3. get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))

  • 作用:指定要获取的位段类型和长度

  • 参数分解

    • BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)
      • unsigned:表示获取无符号整数(值始终 ≥0)
      • dayOfMonth:整数位数长度(例如今天是10月25日,则 dayOfMonth=25
      • 底层逻辑:Redis 会将从偏移量0开始的25个bit转换为一个无符号整数
  • 示例
    如果签到数据为 1011...(二进制),unsigned(25) 会将其转换为十进制整数(如 123456)。

  1. valueAt(0)

    • 作用:指定要获取的起始位偏移量(offset)

    • 参数

      • 0:表示从 BitMap 的第0位开始获取
    • 关键点

      • 偏移量从0开始计数(与 SETBIT/GETBIT 的偏移量规则一致)
      • 配合 unsigned(dayOfMonth) 表示:从第0位开始,获取连续 dayOfMonth 个bit
  2. valueAt(0)

    • 作用:指定要获取的起始位偏移量(offset)

    • 参数

      • 0:表示从 BitMap 的第0位开始获取
    • 关键点

      • 偏移量从0开始计数(与 SETBIT/GETBIT 的偏移量规则一致)
      • 配合 unsigned(dayOfMonth) 表示:从第0位开始,获取连续 dayOfMonth 个bit

相关文章:

  • 数据库 AI 助手测评:Chat2DB、SQLFlow 等工具如何提升开发效率?
  • 前端HTML基础知识
  • 超稳定性理论
  • AI Agent(2):Agent技术架构
  • 2025五一杯B题超详细解题思路
  • 【深度学习新浪潮】小米MiMo-7B报告内容浅析
  • 如何进行 JVM 性能调优?
  • Linux-04-搜索查找类命令
  • mono map
  • 【验证技能】文档要求和好文档注意点
  • 无缝监控:利用 AWS X-Ray 增强 S3 跨账户复制的可见性
  • Java 中使用正则表达式
  • OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传【内含常用设计模式设计示例】
  • 初学Vue之记事本案例
  • 数字智慧方案6165丨智慧医养大数据平台(50页PPT)(文末有下载方式)
  • (34)VTK C++开发示例 ---将图片映射到平面
  • 初学者如何学习AI问答应用开发范式
  • go实现双向链表
  • 《排序算法总结》
  • Three.js在vue中的使用(一)-基础
  • 新势力4月销量出炉:零跑逾4万辆再夺冠,蔚来环比增近六成,小米下滑
  • 北部艳阳高照、南部下冰雹,五一长假首日上海天气很“热闹”
  • 韩国代总统、国务总理韩德洙宣布辞职,将择期宣布参选总统
  • Meta一季度净利增长三成:上调全年资本支出,受关税影响亚洲出口电商广告支出减少
  • 2025五一档新片电影总票房破亿
  • “80后”杨占旭已任辽宁阜新市副市长,曾任辽宁石油化工大学副校长