您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL利用int类型高性能实现签到活动

时间:2023-04-11 14:04:57  来源:  作者:不想洗碗的小明

一:需求背景

产品签到活动需求,对于日活量不高的程序,可以直接使用MySQL去处理,当然数据量不大的话,签到一次,数据库签到表保存一条记录,也是可以的。但是如果类似京东等商城,那种签到活动,日活好几亿,并且并发也很高,这样不断疯狂进行数据库读写操作,MySQL压力是很大的。

 

 

那怎么解决呢?

 

二:解决方案

 

可以利用MySQL,定义一个int类型的字段,4byte=32位,存储一个月的数据,每次签到,改变这个字段,程序代码进行二进制逻辑预算,数据库该值存储十进制,优化成一行数据存一个人一个月的签到记录。一般商城促销活动签到,一个月一个周期已经可以了。

 

三:代码实现

 

代码实现前,先来复习一下逻辑运算和签到逻辑:

 

1.数据库保存签到记录,int类型,4 byte = 32位可以存储一周或者一个月数据
     周1:0000 0001  == 1
     周2:0000 0010  == 2
     周3:0000 0100  == 4
     周4:0000 1000  == 8
     周5:0001 0000  == 16
     周6:0010 0000  == 32
     周7:0100 0000  == 64
    
2.异或 ^ 、与 & 、或 | 逻辑运算:
     异或 ^:两者不一样,eg 1^0,0^1 得出结果就是 1,其他1^1,0^0都是0
     与 &: 只有两者都是是 1 ,eg 1&1 得出结果就是 1,其他都是0
     或 |: 两者有一个是 1 ,eg 1^0,0^1,1^1 得出结果就是 1,其他都是0
    
   

 

所以根据上面分析,可以得出以下模拟每天签到的案例(ps:<< 表示左移):

 

第一天签到:
1 << 0 == 0000 0001 这时数据库存的是 1

第二天签到:
1 << 1 == 0000 0010,此时数据保存前一天签到 0000 0001,所以需要两个数据合成一个,可以用 异或 ^  或者 或 |
0000 0010 | 0000 0001 = 0000 0011  或者  0000 0001 ^ 0000 0010 = 0000 0011
这时数据库存的是 0000 0011 = 3

第三天签到:
1 << 2 == 0000 0100, 数据库存的是 0000 0011
0000 0100  | 0000 0011 = 0000 0111  或者  0000 0100 ^ 0000 0011 = 0000 0111
这时数据库存的是 0000 0111 = 7

第四天没有签到


第五天签到:
1 << 4 == 0001 0000, 数据库存的是 0000 0111
0001 0000 | 0000 0111 = 0001 0111  或者   0001 0000 ^ 0000 0111 = 0001 0111

........

 

业务层代码实现,为了方便,代码模拟一周为一个周期进行签到:

 

  /**
     * 签到并领取奖励
     * @param uid
     * @param day 第几天
     * @return 签到成功返回奖励
     */
public Integer rewardReceiveByDB(String uid, int day) {
        // 查询当前一周,该用户是否签到记录
        LocalDate now = LocalDate.now();
        LocalDateTime startTime = LocalDateTime.of(now.with(DayOfWeek.MONDAY), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(now.with(DayOfWeek.SUNDAY), LocalTime.MAX);
        // 查询是否有本周签到记录,一周只有一条记录
        QueryWrApper<SignLog> wrapper = new QueryWrapper<>();
        wrapper.eq("uid", uid)
                .ge("ctime", startTime)
                .le("ctime", endTime);
        SignLog signLog = signLogService.getOne(wrapper);
        if (signLog == null){
            signLog = new SignLog();
            signLog.setUid(uid);
            signLog.setFlag(0);
        }
        /*
             1 << 2 == 0000 0100, 数据库存的是 0000 0011
            0000 0100  | 0000 0011 = 0000 0111  或者  0000 0100 ^ 0000 0011 = 0000 0111
       */
        int signFlag = signLog.getFlag();
        // 二进制下标 0开始
        signFlag = signFlag | (1 << (day - 1));
        signLog.setFlag(signFlag);
        signLogService.saveOrUpdate(signLog);

        // Integer.bitCount直接统计,签到了几天,发奖励
        long signInDays = Integer.bitCount(signFlag);
        // todo 根据业务需求,发送奖励
        return rewardMap.get(signInDays);
    }

   /**
     * 查看用户在某一天是否签到了
     * @param uid
     * @param day 第几天
     * @return
     */
    @Override
    public boolean getSignStatus(String uid, int day) {
        /**
         * 判断某一天 day 该用户是否签到
         * 可用 某一天 day 签到的 二进制值 跟 当前数据的值 进行 与& 操作,也就是二进制位只有 day 位置是 1,其他都是0,
         *  如果跟它进行 与& 操作 如果数据库值当天签到 就会 等于 1
         */
        LocalDate now = LocalDate.now();
        LocalDateTime startTime = LocalDateTime.of(now.with(DayOfWeek.MONDAY), LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(now.with(DayOfWeek.SUNDAY), LocalTime.MAX);
        // 查询是否有本周签到记录,一周只有一条记录
        QueryWrapper<SignLog> wrapper = new QueryWrapper<>();
        wrapper.eq("uid", uid)
                .ge("ctime", startTime)
                .le("ctime", endTime);
        SignLog signLog = signLogService.getOne(wrapper);
        if (signLog == null){
            return false;
        }
        Integer flag = signLog.getFlag();
        // 当天签到的二进制值
        int signFlag = 1 << (day - 1);
        return (flag & signFlag) == 1;
    }

 

四:总结

 

个人觉得,具体实现根据公司的业务体量来决定。但是条件允许的话,确实可以用位存储来实现。其实redis的一个数据类型bitmap也是根据位来实现。方便一点的,可以知己义工redis的bitmap来实现,这样完全就不用经过数据库,但是如果需要归因的话,数据库保存发送签到奖励的记录即可。

 

本人bitmap实现签到
:https://blog.csdn.NET/qi_ming88/article/detAIls/102716469



Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  Search: MySQL  点击:(6)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  Search: MySQL  点击:(11)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  Search: MySQL  点击:(10)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: MySQL  点击:(24)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10  Search: MySQL  点击:(6)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  Search: MySQL  点击:(28)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  Search: MySQL  点击:(46)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  Search: MySQL  点击:(53)  评论:(0)  加入收藏
为什么高性能场景选用Postgres SQL 而不是 MySQL
一、 数据库简介 TLDR;1.1 MySQL MySQL声称自己是最流行的开源数据库,它属于最流行的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。LAMP...【详细内容】
2024-02-19  Search: MySQL  点击:(38)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  Search: MySQL  点击:(54)  评论:(0)  加入收藏
▌简易百科推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  爱可生开源社区    Tags:MySQL   点击:(6)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  爱可生开源社区  微信公众号  Tags:MySQL   点击:(11)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  MySQL学习  微信公众号  Tags:MySQL   点击:(10)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  字节跳动技术团队    Tags:ByteHouse   点击:(24)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10    dbaplus社群  Tags:MySQL   点击:(6)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  转转技术  微信公众号  Tags:MySQL   点击:(28)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  数据库干货铺  微信公众号  Tags:MySQL   点击:(46)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  编程技术汇    Tags:MySQL   点击:(53)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  数据库干货铺  微信公众号  Tags:MySQL   点击:(54)  评论:(0)  加入收藏
mysql索引失效的场景
MySQL中索引失效是指数据库查询时无法有效利用索引,这可能导致查询性能显著下降。以下是一些常见的MySQL索引失效的场景:1.使用非前导列进行查询: 假设有一个复合索引 (A, B)。...【详细内容】
2024-01-15  小王爱编程  今日头条  Tags:mysql索引   点击:(85)  评论:(0)  加入收藏
站内最新
站内热门
站内头条