您的位置:首页 > 健康 > 养生 > 源码下载网站有哪些_互联网营销师培训学校_宁波seo深度优化平台_爱站网关键词查询网站

源码下载网站有哪些_互联网营销师培训学校_宁波seo深度优化平台_爱站网关键词查询网站

2025/2/23 13:33:02 来源:https://blog.csdn.net/ngczx/article/details/145440300  浏览:    关键词:源码下载网站有哪些_互联网营销师培训学校_宁波seo深度优化平台_爱站网关键词查询网站
源码下载网站有哪些_互联网营销师培训学校_宁波seo深度优化平台_爱站网关键词查询网站

文章目录

      • 为什么需要 bitmap
      • BitMap 的操作
    • * 1. 用户签到 * 2. 检查用户是否签到 * 3. 获取当月签到次数 * 4. 获取当月连续签到次数
    • 功能实现
      • 1. 用户签到实现
      • 2. 检查用户是否签到
      • 3. 获取当月签到次数
      • 4. 获取当月连续签到次数

为什么需要 bitmap

痛点:在 项目开发中经常会用到签到的功能,如果用户有量很少,签到信息直接存储在数据库中还是很合理的,但是随着用户量的增加,100 万用户,就算一个用户一年签到 20 次就已经 2000 万数据了,增长的非常快,并且查询的时候效率也低。

为了解决这个问题可以用 Bitmap 的数据结构。

用 1 来表示签到,用 0 来表示没有签到。

对于一个月来说,从第一个开始签到。一个月最多 31 天,用 31bit 来表示用户签到。一个月只需要两个字节。

一个用户一个月签到的信息也就只有一条,这样大大减少了数据库的压力。

布隆过滤器底层也是 bitmap。 在 redis 中使用 string 来实现 bitmap。最大存储上线 512,最大时 2 的 32 次方比特位。

BitMap 的操作

功能分析:

对于用户签到数据,如果直接采用数据库存储,当出现高并发访问时,对数据库压力会很大,例如双十一签到活动。这时候应该采用缓存,以减轻数据库的压力,Redis是高性能的内存数据库,适用于这样的场景。

另外如果系统的用户量很多,每次签到都插入一条记录,那么数据库表增长就很快。如果系统两百万用户,一个月平均签到十次,那么就是两千万数据量,mysql 一张表大概也就是两千万。

签到出来的数据

setbit  bm1  0 1  在第0个位置赋值为1

这个图中可以看出来是第 1、2、7 天签到的。

判断第二天是否签到,getbit 如果等于 1 说明用户在这一天完成了签到功能;

get bm1 1  //判断是否等于1

bitpos 判断开始签到的位置

实现签到的代码 存储在 redis 中的格式

sign:userID:202401,这样每一个用户都是一个 key.

@Override
public Result sign() {// 1.获取当前登录用户Long userId = UserHolder.getUser().getId();// 2.获取日期LocalDateTime now = LocalDateTime.now(); //获取当前的时间// 3.拼接keyString keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM")); //当前月String key = USER_SIGN_KEY + userId + keySuffix;// 4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth(); //当前天数// 5.写入Redis SETBIT key offset 1stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);return Result.ok();
}

连续签到次数


* 1. 用户签到 * 2. 检查用户是否签到 * 3. 获取当月签到次数 * 4. 获取当月连续签到次数

创建用户的签到数据库表:

功能实现

1. 用户签到实现

@Override
public void signIn() {// 获取当前登录的用户IdLong userId = SecurityUtils.getUserId();//获取日期LocalDateTime now = LocalDateTime.now();// 获取当前的月份String keySuffix=now.format(DateTimeFormatter.ofPattern(":yyyyMM"));//拼接String   key= SignRedisConstant.SIGN_KEY + userId+keySuffix;int dayOfMonth = now.getDayOfMonth();redisTemplate.opsForValue().setBit(key,dayOfMonth-1,true);
}

还需要做异步任务,将数据同步到数据库中去。

待做:用定时任务或者异步操作更新数据库中的签到信息。

2. 检查用户是否签到

将获取 key 的方法封装起来

public class RedisUtil {public static String getSign() {Long userId = SecurityUtils.getUserId();LocalDateTime now = LocalDateTime.now();String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));return SignRedisConstant.SIGN_KEY + userId + keySuffix;}public static LocalDateTime getNow() {return  LocalDateTime.now();}
}
@Override
public boolean isSignIn() {String keySuffix = RedisUtil.getSign();int dayOfMonth = RedisUtil.getNow().getDayOfMonth();return redisTemplate.opsForValue().getBit(keySuffix, dayOfMonth - 1);
}

3. 获取当月签到次数

@Override
public int getCurrentMonth() {String keySuffix = RedisUtil.getSign();String str = (String) redisTemplate.opsForValue().get(keySuffix);int count = 0;for (int i = 0; i < str.length(); i++) {if (str.charAt(i) == '1') {count++;}}return count;
}

4. 获取当月连续签到次数

从最后一个开始一直找到第一个为 0 的地方,和 1 进行与操作就是拿到最后一个数字的。

@Override
public int getContinuousSignInCount() {String keySuffix = RedisUtil.getSign();int dayOfMonth = RedisUtil.getNow().getDayOfMonth();List<Long> result = redisTemplate.opsForValue().bitField(keySuffix, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if (result == null || result.size() == 0) {return 0;}Long num = result.get(0);if (num == null || num == 0) {return 0;}int count = 0;//主要是这一段的逻辑while (true) {if ((num & 1) == 0) {break;} else {count++;}num = num >> 1;}return count;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com