宝哥软件园

PHP使用redis bitMap实现签到功能

编辑:宝哥软件园 来源:互联网 时间:2021-08-19

一、需求

记录用户登录,查询用户登录。

二、技术方案

1.使用mysql(max_time字段是连续登录天数)

思考:

(1)用户登录时,插入记录,根据create_time查询昨天是否登录。如果有签到,max_time在原基础1,否则max_time=0

(2)检查登录,根据user_id和create_time查询记录是否存在;如果它不存在,则意味着没有登录。

2.使用redis位图功能

思考:

(1)每个用户每个月都有单独的redis记录,比如00101010101010,从左到右表示01-31天(每个月只有几天)。(2)每月8日凌晨,将redis记录统一移动到mysql,如记录图所示。

(3)当月从redis查询,上月从mysql获取

3.方案比较

示例:10,000名用户登录365天

方案一:mysql插入365万条记录

频繁请求数据库进行一些日志记录会浪费服务器开销。随着时间的推移,数据快速增长,海量数据的检索效率不高。同时,time create_time只能作为区间查询条件,数据量大肯定慢

方案二:mysql插入12w条记录

节省空间,每个用户每天只占用1bit空间,1w用户每天产生10,000 bits=1050字节的数据,约1kb。内存操作很快

3.实施(方案2)

(1)关键结构

前缀_年_月:用户标识-符号_ 2019 _ 10:01

查询:

单曲:keysign _ 2019 _ 10 _ 01

全部:钥匙符号_*

月份:keys标志_2019_10:*

(2)mysql表结构

(3)代码(列出一个调用方法和三个类)

登记方法

公共静态函数userSignIn($ userId){ $ Time=Time();$today=date('d ',$ time);$year=date('Y ',$ time);$month=日期(' m ',$ time);$signModel=new Sign($userId,$year,$ month);//1.今天查询用户的登录信息:$ today sign=$ sign model-getsign log($ today);if($ today sign){ return self :3360 jsonarr(-1,'您已经签入',[]);}请尝试{ db :3360 starttrans();$ SignMoDEL-SetSignLog($今日);//4,如果(self : sing _ in _ score 0){ $ data core[' order _ id ']=$ userid,则给分。' _'.今日美元;$ DataScore[' type ']=2;//2、登录$ datacore['备注']='登录获取积分';finance : updateuser SCORE(finance :3360 opt _ ADD,$userId,self:SING_IN_SCORE,$ datacore);} $ code=' 0$msg=“登录成功”;$ SCORE=self : sing _ IN _ SCORE;db : commit();} catch(异常$ e){ db : roll back();$ code='-2 ';$msg=“登录失败”;$ score=0;}返回self:jsonArr($code,$msg,[' score '=$ score]);} redis基类

?phpnamespace app common redis db1;/** * redis操作类*/class RedisAbstract{ /** *连接的库* @ var int */protected $ _ db=1;//数据库名受保护的$ _ tableName=//表名static $ redis=null public function _ _ construct(){ return $ this-getRedis();} public function _ calcKey($ id){ return $ this-_ tableName .$ id} /** *查找key * @ param $ key * @返回数组* @抛出例外* @作者wenzhen-Chen */public function key($ key){ return $ this-getRedis()-keys($ this-_ calcKey($ key));} /** * 获取是否开启缓存的设置参数* * @返回boolean */public function _ GetEnable(){ $ conf=Config(' redis ');返回$ conf[' enable '];} /** * 获取存储连接* * @ static var null $ Redis * @ return Redis * @抛出异常*/公共函数getRedis() { if(!self : $ redis){ $ conf=Config(' redis ');if(!$ conf){ 0抛出新异常(' redis连接必须设置');} self : $ Redis=new Redis();self : $ redis-connect($ conf[' host '],$ conf[' port ']);self : $ redis-select($ this-_ db);} return self : $ redis }/* * *设置位图* @ param $ key * @ param $ offset * @ param $ value * @ param int $ time * @ return int | null * @抛出异常* @作者文珍-陈*/公开函数setBit($key,$ offset,$ value,$time=0) { if(!$ this-_ GetEnable()){ 0返回null } $ result=$ this-getRedis()-setBit($ key,$offset,$ value);if($ time){ $ this-getRedis()-expire($ key,$ time);}返回$ result} /** *获取位图* @ param $ key * @ param $ offset * @ return int | null * @抛出异常* @作者文珍-陈*/公共函数getBit($ key,$offset) { if(!$ this-_ GetEnable()){ 0返回null}返回$this-getRedis()-getBit($key,$ offset);} /** * 统计位图* @ param $ key * @ return int | null * @抛出异常* @作者文珍-陈*/公共函数bitCount($ key){ if(!$ this-_ GetEnable()){ 0返回null}返回$ this-getRedis()-bitCount($ key);} /** * 位图操作* @ param $操作* @param $retKey * @param mixed.$ key * @ return int | null * @抛出 Exception * @作者wenzhen-Chen */公共函数bitOp($ operation,$retKey,$key) { if(!$ this-_ GetEnable()){ 0返回null}返回$ this-getRedis()-bitOp($ operation,$retKey,$ key);} /** * 计算在某段位图中一或0第一次出现的位置* @ param $ key * @ param $ bit 1/0 * @ param $ start * @ param null $ end * @ return int | null * @抛出异常* @作者文珍-陈*/公共函数BitPos($ key,$ bit,$ start,$end=null) { if(!$ this-_ GetEnable()){ 0返回null}返回$this-getRedis()-bitpos($key,$bit,$start,$ end);} /** * 删除数据* @ param $ key * @ return int | null * @抛出异常* @作者文珍-陈*/公共函数del($ key){ if(!$ this-_ GetEnable()){ 0返回null}返回$ this-getRedis()-del($ key);}} 签到存储操作类

?php/** *由PhpStorm创建*用户: Administrator *日期: 2019/9/30 *时间: 14:42 */命名空间app common redis db1班级标志扩展了再贴现{ public $ KeySign=' Sign//签到记录key public function _ _ construct($ userId,$year,$ month){ parent : _ _ construct();//设置当前用户签到记录的key $this-keySign=$this-keySign .'_' .一年一美元。'_' .一个月。':' .$ userId} /** *用户签到* @ param $day * @ return int | null * @抛出异常* @作者文珍-陈*/公开函数setSignLog($ day){ return $ this-setBit($ this-key sign,$ day,1);} /** * 查询签到记录* @ param $ day * @ return int | null * @抛出异常* @作者文珍-陈*/公开函数getSignLog($userId,$ day){ return $ this-getBit($ this-key sign,$ day);} /** * 删除签到记录* @ return int | null * @抛出 Exception * @作者wenzhen-Chen */public函数DelSignLig(){ return $ this-del($ this-KeySign);}} 定时更新至关系型数据库的类

?php/** *由PhpStorm创建。*用户:管理员*日期: 2019/10/4 *时间: 19:03 */命名空间应用公共商务使用app common mysql SignLog使用app common redis db1 SignCron类{ /** *同步用户签到记录* @抛出异常*/公共静态函数addUserSignLogToMysql(){ $ data=[];$ Time=Time();//1、计算上月的年份、月份$ DataTiME=common :3360 getmonthtimebykey(0);$year=date('Y ',$ dataTime[' start _ time ']);$month=date('m ',$ dataTime[' start _ time ']);//2、查询签到记录的密钥$signModel=新签名(0,$年,$月);$keys=$signModel-keys('sign_ ').一年一美元。'_' .一个月。':*');foreach($ key as $ key){ $ BitLog=' ';//用户当月签到记录$userData=explode(': ',$ key);$ userId=$ userData[1];//3、循环查询用户是否签到(这里没按每月天数存储,直接都存31天了)为($ I=1;$ I=31 $ I){ $ Issign=$ SignMoDEL-GetBit($ key,$ I);$bitLog .=$ Issign } $ data[]=[' user _ id '=$ userId,' year'=$year,' month'=$month,' bit_log'=$bitLog,' create_time'=$time,' update _ time '=$ time];} //4、插入日志if($ data){ $ logModel=new sign log();$logModel-insertAll($data,',100);} }}总结

以上所述是小编给大家介绍的服务器端编程语言(专业超文本预处理器的缩写)使用存储位图位图实现签到功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

更多资讯
游戏推荐
更多+