利用redis实现用户签到

10 篇文章 0 订阅

很多网站都提供了签到功能(这里不考虑数据落地事宜),并且需要展示最近一个月的签到情况,如果使用bitmap我们怎么做?一言不合亮代码!

<?php
$redis = new Redis();
$redis->connect('127.0.0.1');
 
 
//用户uid
$uid = 1;
 
//记录有uid的key
$cacheKey = sprintf("sign_%d", $uid);
 
//开始有签到功能的日期
$startDate = '2017-01-01';
 
//今天的日期
$todayDate = '2017-01-21';
 
//计算offset
$startTime = strtotime($startDate);
$todayTime = strtotime($todayDate);
$offset = floor(($todayTime - $startTime) / 86400);
 
echo "今天是第{$offset}天" . PHP_EOL;
 
//签到
//一年一个用户会占用多少空间呢?大约365/8=45.625个字节,好小,有木有被惊呆?
$redis->setBit($cacheKey, $offset, 1);
 
//查询签到情况
$bitStatus = $redis->getBit($cacheKey, $offset);
echo 1 == $bitStatus ? '今天已经签到啦' : '还没有签到呢';
echo PHP_EOL;
 
//计算总签到次数
echo $redis->bitCount($cacheKey) . PHP_EOL;
 
/**
* 计算某段时间内的签到次数
* 很不幸啊,bitCount虽然提供了start和end参数,但是这个说的是字符串的位置,而不是对应"位"的位置
* 幸运的是我们可以通过get命令将value取出来,自己解析。并且这个value不会太大,上面计算过一年一个用户只需要45个字节
* 给我们的网站定一个小目标,运行30年,那么一共需要1.31KB(就问你屌不屌?)
*/
//这是个错误的计算方式
echo $redis->bitCount($cacheKey, 0, 20) . PHP_EOL;

BITCOUNT的坑

redis> BITCOUNT bits
(integer) 0
redis> SETBIT bits 1 1          
(integer) 0
redis> SETBIT bits 2 1
(integer) 0
redis> BITCOUNT bits
(integer) 2
redis> BITCOUNT bits 2 -1
(integer) 0

为什么我设置了bitcount的start后会取不到值?
“redis的setbit修改的是bit位置,而bitcount检查的是byte位置,两者相差有8的倍数”,再看文档确实是有这个说明,不过太不明显了
所以在setbit 前把offset * 8 才可以。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 10);
 
// 乘以8的原因是这个操作修改的是bit位置
$start = 1;
$offset = $start * 8;
$redis->setBit('bit', $offset, 1);
$count = $redis->bitCount('bit', $start, -1);
var_dump($count);

 

参考:https://blog.csdn.net/fly910905/article/details/82629687

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Redis实现签到功能,可以考虑使用Redis中的Set和Sorted Set数据结构。 首先,我们可以使用Set来存储用户每日签到的记录,每个用户对应一个Set。在签到时,只需要将当前日期作为元素加入到该用户的Set中即可。 接下来,我们可以使用Sorted Set来记录用户的连续签到天数。每个用户对应一个Sorted Set,键名可以以“user:连续签到天数”来命名。在用户签到时,我们可以使用Redis的INCRBY命令来将该用户的连续签到天数加1,并将该用户当前的连续签到天数作为Sorted Set中该用户的分值。 下面是一个使用Redis实现签到功能的示例代码: ```python import redis from datetime import datetime, timedelta # 连接Redis redis_client = redis.Redis(host='localhost', port=6379, db=0) # 用户签到函数 def checkin(user_id): # 获取当前日期 today = datetime.now().strftime('%Y-%m-%d') # 将用户签到记录存入Set中 redis_client.sadd(f'user:{user_id}:checkin', today) # 获取用户连续签到天数 continuous_days = redis_client.zscore(f'user:{user_id}:continuous_days', user_id) # 如果用户从未签到过,则将其连续签到天数初始化为1 if not continuous_days: redis_client.zadd(f'user:{user_id}:continuous_days', {user_id: 1}) else: # 获取昨天的日期 yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') # 如果用户昨天已经签到,则将其连续签到天数加1 if redis_client.sismember(f'user:{user_id}:checkin', yesterday): new_continuous_days = int(continuous_days) + 1 redis_client.zadd(f'user:{user_id}:continuous_days', {user_id: new_continuous_days}) else: # 如果用户昨天未签到,则将其连续签到天数重置为1 redis_client.zadd(f'user:{user_id}:continuous_days', {user_id: 1}) ``` 在上面的示例代码中,我们通过`sadd`命令将用户签到记录存入Set中,通过`zscore`命令获取用户的连续签到天数,通过`zadd`命令将用户的连续签到天数更新到Sorted Set中。同时,为了方便判断用户的连续签到情况,我们还使用`sismember`命令判断用户昨天是否已经签到过。 需要注意的是,上述示例代码仅为演示使用,实际使用时还需要考虑并发情况下的数据安全性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值