欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis實現(xiàn)用戶簽到的示例代碼

 更新時間:2024年09月27日 09:49:20   作者:雪頂貓的鱷  
Redis的位圖可以高效實現(xiàn)用戶簽到功能,每個bit位對應一個簽到狀態(tài),節(jié)省存儲空間,利用SETBIT、GETBIT等命令操作簽到數(shù)據(jù),可統(tǒng)計連續(xù)簽到天數(shù)和本月簽到情況,感興趣的可以了解一下

一、BitMap功能演示

我們針對簽到功能完全可以通過mysql來完成,比如說以下這張表

在這里插入圖片描述

用戶一次簽到,就是一條記錄,假如有1000萬用戶,平均每人每年簽到次數(shù)為10次,則這張表一年的數(shù)據(jù)量為 1億條

每簽到一次需要使用(8 + 8 + 1 + 1 + 3 + 1)共22 字節(jié)的內(nèi)存,一個月則最多需要600多字節(jié)

我們?nèi)绾文軌蚝喕稽c呢?其實可以考慮小時候一個挺常見的方案,就是小時候,咱們準備一張小小的卡片,你只要簽到就打上一個勾,我最后判斷你是否簽到,其實只需要到小卡片上看一看就知道了

我們可以采用類似這樣的方案來實現(xiàn)我們的簽到需求。

我們按月來統(tǒng)計用戶簽到信息,簽到記錄為1,未簽到則記錄為0.

把每一個bit位對應當月的每一天,形成了映射關系。用0和1標示業(yè)務狀態(tài),這種思路就稱為位圖(BitMap)。這樣我們就用極小的空間,來實現(xiàn)了大量數(shù)據(jù)的表示

Redis中是利用string類型數(shù)據(jù)結(jié)構(gòu)實現(xiàn)BitMap,因此最大上限是512M,轉(zhuǎn)換為bit則是 2^32個bit位。

在這里插入圖片描述

BitMap的操作命令有:

  • SETBIT:向指定位置(offset)存入一個0或1
  • GETBIT :獲取指定位置(offset)的bit值
  • BITCOUNT :統(tǒng)計BitMap中值為1的bit位的數(shù)量
  • BITFIELD :操作(查詢、修改、自增)BitMap中bit數(shù)組中的指定位置(offset)的值
  • BITFIELD_RO :獲取BitMap中bit數(shù)組,并以十進制形式返回
  • BITOP :將多個BitMap的結(jié)果做位運算(與 、或、異或)
  • BITPOS :查找bit數(shù)組中指定范圍內(nèi)第一個0或1出現(xiàn)的位置

二、實現(xiàn)簽到功能

需求:實現(xiàn)簽到接口,將當前用戶當天簽到信息保存到Redis中

思路:我們可以把年和月作為bitMap的key,然后保存到一個bitMap中,每次簽到就到對應的位上把數(shù)字從0變成1,只要對應是1,就表明說明這一天已經(jīng)簽到了,反之則沒有簽到。

我們通過接口文檔發(fā)現(xiàn),此接口并沒有傳遞任何的參數(shù),沒有參數(shù)怎么確實是哪一天簽到呢?這個很容易,可以通過后臺代碼直接獲取即可,然后到對應的地址上去修改bitMap。

在這里插入圖片描述

代碼UserController

 @PostMapping("/sign")
 public Result sign(){
    return userService.sign();
 }

UserServiceImpl

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

三、簽到統(tǒng)計

問題1: 什么叫做連續(xù)簽到天數(shù)?
從最后一次簽到開始向前統(tǒng)計,直到遇到第一次未簽到為止,計算總的簽到次數(shù),就是連續(xù)簽到天數(shù)。

在這里插入圖片描述

Java邏輯代碼:獲得當前這個月的最后一次簽到數(shù)據(jù),定義一個計數(shù)器,然后不停的向前統(tǒng)計,直到獲得第一個非0的數(shù)字即可,每得到一個非0的數(shù)字計數(shù)器+1,直到遍歷完所有的數(shù)據(jù),就可以獲得當前月的簽到總天數(shù)了

問題2: 如何得到本月到今天為止的所有簽到數(shù)據(jù)?
BITFIELD key GET u[dayOfMonth] 0
假設今天是10號,那么我們就可以從當前月的第一天開始,獲得到當前這一天的位數(shù),是10號,那么就是10位,去拿這段時間的數(shù)據(jù),就能拿到所有的數(shù)據(jù)了,那么這10天里邊簽到了多少次呢?統(tǒng)計有多少個1即可。

問題3: 如何從后向前遍歷每個bit位?
注意:bitMap返回的數(shù)據(jù)是10進制,哪假如說返回一個數(shù)字8,那么我哪兒知道到底哪些是0,哪些是1呢?我們只需要讓得到的10進制數(shù)字和1做與運算就可以了,因為1只有遇見1 才是1,其他數(shù)字都是0 ,我們把簽到結(jié)果和1進行與操作,每與一次,就把簽到結(jié)果向右移動一位,依次內(nèi)推,我們就能完成逐個遍歷的效果了。

需求:實現(xiàn)下面接口,統(tǒng)計當前用戶截止當前時間在本月的連續(xù)簽到天數(shù)

有用戶有時間我們就可以組織出對應的key,此時就能找到這個用戶截止這天的所有簽到記錄,再根據(jù)這套算法,就能統(tǒng)計出來他連續(xù)簽到的次數(shù)了

在這里插入圖片描述

代碼UserController

@GetMapping("/sign/count")
public Result signCount(){
    return userService.signCount();
}

UserServiceImpl

@Override
public Result signCount() {
    // 1.獲取當前登錄用戶
    Long userId = UserHolder.getUser().getId();
    // 2.獲取日期
    LocalDateTime now = LocalDateTime.now();
    // 3.拼接key
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + keySuffix;
    // 4.獲取今天是本月的第幾天
    int dayOfMonth = now.getDayOfMonth();
    // 5.獲取本月截止今天為止的所有的簽到記錄,返回的是一個十進制的數(shù)字 BITFIELD sign:5:202203 GET u14 0
    List<Long> result = stringRedisTemplate.opsForValue().bitField(
            key,
            BitFieldSubCommands.create()
                    .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
    );
    if (result == null || result.isEmpty()) {
        // 沒有任何簽到結(jié)果
        return Result.ok(0);
    }
    Long num = result.get(0);
    if (num == null || num == 0) {
        return Result.ok(0);
    }
    // 6.循環(huán)遍歷
    int count = 0;
    while (true) {
        // 6.1.讓這個數(shù)字與1做與運算,得到數(shù)字的最后一個bit位  // 判斷這個bit位是否為0
        if ((num & 1) == 0) {
            // 如果為0,說明未簽到,結(jié)束
            break;
        }else {
            // 如果不為0,說明已簽到,計數(shù)器+1
            count++;
        }
        // 把數(shù)字右移一位,拋棄最后一個bit位,繼續(xù)下一個bit位
        num >>>= 1;
    }
    return Result.ok(count);
}

到此這篇關于Redis實現(xiàn)用戶簽到的示例代碼的文章就介紹到這了,更多相關Redis 用戶簽到內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • redis list類型命令的實現(xiàn)

    redis list類型命令的實現(xiàn)

    本文主要介紹了redis list類型命令的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • 詳解用Redis實現(xiàn)Session功能

    詳解用Redis實現(xiàn)Session功能

    本篇文章主要介紹了用Redis實現(xiàn)Session功能,具有一定的參考價值,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。
    2016-12-12
  • RedisAPI原子性操作及原理解析

    RedisAPI原子性操作及原理解析

    這篇文章主要介紹了RedisAPI原子性操作及原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-12-12
  • Redis緩存lettuce更換為Jedis的實現(xiàn)步驟

    Redis緩存lettuce更換為Jedis的實現(xiàn)步驟

    在springboot中引入spring-boot-starter-data-redis依賴時,默認使用的是lettuce,如果不想使用lettuce而是使用Jedis連接池,本文主要介紹了Redis緩存lettuce更換為Jedis的實現(xiàn)步驟,感興趣的可以了解一下
    2024-08-08
  • 使用Ruby腳本部署Redis Cluster集群步驟講解

    使用Ruby腳本部署Redis Cluster集群步驟講解

    今天小編就為大家分享一篇關于使用Ruby腳本部署Redis Cluster集群步驟講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Redis 通過 RDB 方式進行數(shù)據(jù)備份與還原的方法

    Redis 通過 RDB 方式進行數(shù)據(jù)備份與還原的方法

    這篇文章主要介紹了Redis 通過 RDB 方式進行數(shù)據(jù)備份與還原,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • RedisDesktopManager?連接redis的方法

    RedisDesktopManager?連接redis的方法

    這篇文章主要介紹了RedisDesktopManager?連接redis,需要的朋友可以參考下
    2023-08-08
  • 阿里云官方Redis開發(fā)規(guī)范總結(jié)

    阿里云官方Redis開發(fā)規(guī)范總結(jié)

    本文主要介紹了阿里云官方Redis開發(fā)規(guī)范總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • redis服務器允許遠程主機訪問的方法

    redis服務器允許遠程主機訪問的方法

    今天小編就為大家分享一篇redis服務器允許遠程主機訪問的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Redis中鍵值過期操作示例詳解

    Redis中鍵值過期操作示例詳解

    這篇文章主要給大家介紹了關于Redis中鍵值過期操作的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-11-11

最新評論