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

微服務(wù)?Spring?Boot?整合?Redis?BitMap?實(shí)現(xiàn)?簽到與統(tǒng)計功能

 更新時間:2023年01月09日 16:11:11   作者:Bug?終結(jié)者  
這篇文章主要介紹了微服務(wù)?Spring?Boot?整合?Redis?BitMap?實(shí)現(xiàn)?簽到與統(tǒng)計功能,文章簡單介紹了Redis BitMap 基本用法結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

引言

在各個項目中,我們都可能需要用到簽到和 統(tǒng)計功能。 簽到后會給用戶一些禮品以此來吸引用戶持續(xù)在該平臺進(jìn)行活躍。

簽到功能,我們可以通過Redis中的 BitMap功能來實(shí)現(xiàn)

一、Redis BitMap 基本用法

?BitMap 基本語法、指令

簽到功能我們可以使用MySQL來完成,比如下表:

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

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

這樣的壞處,占用內(nèi)存太大了,極大的消耗內(nèi)存空間!

我們可以根據(jù) Redis中 提供的 BitMap 位圖功能來實(shí)現(xiàn),每次簽到與未簽到用0 或1 來標(biāo)識 ,一次存31個數(shù)字,只用了2字節(jié) 這樣我們就用極小的空間實(shí)現(xiàn)了簽到功能

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ù)組,并以十進(jìn)制形式返回
  • BITOP :將多個BitMap的結(jié)果做位運(yùn)算(與 、或、異或)
  • BITPOS :查找bit數(shù)組中指定范圍內(nèi)第一個0或1出現(xiàn)的位置

?使用 BitMap 完成功能實(shí)現(xiàn)

服務(wù)器Redis版本采用 6.2

進(jìn)入redis查詢 SETBIT 命令

新增key 進(jìn)行存儲

查詢 GETBIT命令

查看指定坐標(biāo)的簽到狀態(tài)

查詢 BITFIELD

無符號查詢

BITPOS 查詢1 和 0 第一次出現(xiàn)的坐標(biāo)

二、SpringBoot 整合 Redis 實(shí)現(xiàn)簽到 功能

??需求介紹

采用BitMap實(shí)現(xiàn)簽到功能

實(shí)現(xiàn)簽到接口,將當(dāng)前用戶當(dāng)天簽到信息保存到Redis中

思路分析:

我們可以把 年和月 作為BitMap的key,然后保存到一個BitMap中,每次簽到就到對應(yīng)的位上把數(shù)字從0 變?yōu)?,只要是1,就代表是這一天簽到了,反之咋沒有簽到。

實(shí)現(xiàn)簽到接口,將當(dāng)前用戶當(dāng)天簽到信息保存至Redis中

說明
請求方式POST
請求路徑/user/sign
請求參數(shù)
返回值

提示: 因為BitMap 底層是基于String數(shù)據(jù)結(jié)構(gòu),因此其操作都封裝在字符串操作中了。

?核心源碼

UserController

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

UserServiceImpl

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 = RedisConstants.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();
}

接口進(jìn)行測試

ApiFox進(jìn)行測試

查看Redis 數(shù)據(jù)

三、SpringBoot 整合Redis 實(shí)現(xiàn) 簽到統(tǒng)計功能

問題一: 什么叫做連續(xù)簽到天數(shù)?

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

邏輯分析:

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

問題二: 如何得到本月到今天為止的所有簽到數(shù)據(jù)?

BITFIELD key GET u[dayOfMonth] 0

假設(shè)今天是7號,那么我們就可以從當(dāng)前月的第一天開始,獲得到當(dāng)前這一天的位數(shù),是7號,那么就是7位,去拿這段時間的數(shù)據(jù),就能拿到所有的數(shù)據(jù)了,那么這7天里邊簽到了多少次呢?統(tǒng)計有多少個1即可。

**問題三:**如何從后向前遍歷每個Bit位?

注意:bitMap返回的數(shù)據(jù)是10進(jìn)制,哪假如說返回一個數(shù)字8,那么我哪兒知道到底哪些是0,哪些是1呢?

我們只需要讓得到的10進(jìn)制數(shù)字和1做與運(yùn)算就可以了,因為1只有遇見1 才是1,其他數(shù)字都是0 ,我們把簽到結(jié)果和1進(jìn)行與操作,每與一次,就把簽到結(jié)果向右移動一位,依次內(nèi)推,我們就能完成逐個遍歷的效果了。

需求:

實(shí)現(xiàn)以下接口,統(tǒng)計當(dāng)前截至當(dāng)前時間在本月的連續(xù)天數(shù)

說明請求方式GET請求路徑/user/sign/count請求參數(shù)無返回值連續(xù)簽到的天數(shù)

說明
請求方式GET
請求路徑/user/sign/count
請求參數(shù)
返回值連續(xù)簽到的天數(shù)

核心源碼

UserController

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

UserServiceImpl

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 = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
    //4. 獲取今天是本月的第幾天
    int dayOfMonth = now.getDayOfMonth();
    //5. 獲取本月截至今天為止的所有的簽到記錄,返回的是一個十進(jìn)制的數(shù)字 BITFIELD sign:5:202301 GET u3 0
    List<Long> result = stringRedisTemplate.opsForValue().bitField(
        key,
        BitFieldSubCommands.create()
        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
    //沒有任務(wù)簽到結(jié)果
    if (result == null || result.isEmpty()) {
        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 做與運(yùn)算,得到數(shù)字的最后一個bit位 判斷這個數(shù)字是否為0
        if ((num & 1) == 0) {
            //如果為0,簽到結(jié)束
            break;
        } else {
            count ++;
        }
        num >>>= 1;
    }
    return Result.ok(count);
}

進(jìn)行測試

查看 Redis 變量

從今天開始,往前查詢 連續(xù)簽到的天數(shù),結(jié)果為2 測試無誤!

四、關(guān)于使用bitmap來解決緩存穿透的方案

回顧緩存穿透

發(fā)起了一個數(shù)據(jù)庫不存在的,redis里邊也不存在的數(shù)據(jù),通常你可以把他看成一個攻擊

解決方案:

  • 判斷id<0
  • 數(shù)據(jù)庫為空的話,向redis里邊把這個空數(shù)據(jù)緩存起來

第一種解決方案:遇到的問題是如果用戶訪問的是id不存在的數(shù)據(jù),則此時就無法生效

第二種解決方案:遇到的問題是:如果是不同的id那就可以防止下次過來直擊數(shù)據(jù)

所以我們?nèi)绾谓鉀Q呢?

我們可以將數(shù)據(jù)庫的數(shù)據(jù),所對應(yīng)的id寫入到一個list集合中,當(dāng)用戶過來訪問的時候,我們直接去判斷l(xiāng)ist中是否包含當(dāng)前的要查詢的數(shù)據(jù),如果說用戶要查詢的id數(shù)據(jù)并不在list集合中,則直接返回,如果list中包含對應(yīng)查詢的id數(shù)據(jù),則說明不是一次緩存穿透數(shù)據(jù),則直接放行。

現(xiàn)在的問題是這個主鍵其實(shí)并沒有那么短,而是很長的一個 主鍵

哪怕你單獨(dú)去提取這個主鍵,但是在 11年左右,淘寶的商品總量就已經(jīng)超過10億個

所以如果采用以上方案,這個list也會很大,所以我們可以使用bitmap來減少list的存儲空間

我們可以把list數(shù)據(jù)抽象成一個非常大的bitmap,我們不再使用list,而是將db中的id數(shù)據(jù)利用哈希思想,比如:

id 求余bitmap長度 :id % bitmap.size = 算出當(dāng)前這個id對應(yīng)應(yīng)該落在bitmap的哪個索引上,然后將這個值從0變成1,然后當(dāng)用戶來查詢數(shù)據(jù)時,此時已經(jīng)沒有了list,讓用戶用他查詢的id去用相同的哈希算法, 算出來當(dāng)前這個id應(yīng)當(dāng)落在bitmap的哪一位,然后判斷這一位是0,還是1,如果是0則表明這一位上的數(shù)據(jù)一定不存在,采用這種方式來處理,需要重點(diǎn)考慮一個事情,就是誤差率,所謂的誤差率就是指當(dāng)發(fā)生哈希沖突的時候,產(chǎn)生的誤差。

?小結(jié)

以上就是【Bug 終結(jié)者】對 微服務(wù) Spring Boot 整合 Redis BitMap 實(shí)現(xiàn) 簽到與統(tǒng)計 的簡單介紹,簽到功能是很常用的,在項目中,是一個不錯的亮點(diǎn),統(tǒng)計功能也是各大系統(tǒng)中比較重要的功能,簽到完成后,去統(tǒng)計本月的連續(xù) 簽到記錄,來給予獎勵,可大大增加用戶對系統(tǒng)的活躍度 技術(shù)改變世界?。?!

到此這篇關(guān)于微服務(wù) Spring Boot 整合 Redis BitMap 實(shí)現(xiàn) 簽到與統(tǒng)計的文章就介紹到這了,更多相關(guān)Spring Boot 整合 Redis BitMap 實(shí)現(xiàn) 簽到與統(tǒng)計內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于Spring?Ioc和DI注解的問題

    關(guān)于Spring?Ioc和DI注解的問題

    這篇文章主要介紹了Spring?Ioc和DI注解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • SpringSecurity攔截器鏈的使用詳解

    SpringSecurity攔截器鏈的使用詳解

    這篇文章主要介紹了SpringSecurity攔截器鏈的使用詳解,webSecurity的build方法最終調(diào)用的是doBuild方法,doBuild方法調(diào)用的是webSecurity的performBuild方法,webSecurity完成所有過濾器的插件,最終返回的是過濾器鏈代理類filterChainProxy,需要的朋友可以參考下
    2023-11-11
  • Mybatis開發(fā)環(huán)境搭建實(shí)現(xiàn)數(shù)據(jù)的增刪改查功能

    Mybatis開發(fā)環(huán)境搭建實(shí)現(xiàn)數(shù)據(jù)的增刪改查功能

    這篇文章主要介紹了 Mybatis開發(fā)環(huán)境搭建實(shí)現(xiàn)數(shù)據(jù)的增刪改查功能,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • 必須詳細(xì)與全面的Java開發(fā)環(huán)境搭建圖文教程

    必須詳細(xì)與全面的Java開發(fā)環(huán)境搭建圖文教程

    本篇文章內(nèi)容包括:Linux理論與實(shí)操,MySQL實(shí)操,JDK實(shí)操,Tomcat實(shí)操和Tomcat實(shí)操,需要的朋友可以參考下
    2019-11-11
  • mybatis3中@SelectProvider傳遞參數(shù)方式

    mybatis3中@SelectProvider傳遞參數(shù)方式

    這篇文章主要介紹了mybatis3中@SelectProvider傳遞參數(shù)方式。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot應(yīng)用自定義logback日志詳解

    SpringBoot應(yīng)用自定義logback日志詳解

    默認(rèn)情況下,SpringBoot內(nèi)部使用logback作為系統(tǒng)日志實(shí)現(xiàn)的框架,將日志輸出到控制臺,不會寫到日志文件。本篇文章主要講解下如何自定義logabck.xml以及對logback文件中配置做一個詳解,需要的可以參考一下
    2022-10-10
  • 詳細(xì)解讀Java編程中面向字符的輸入流

    詳細(xì)解讀Java編程中面向字符的輸入流

    這篇文章主要介紹了Java中面向字符的輸入和輸出流,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-10-10
  • Java交換map的key和value值的步驟和代碼示例

    Java交換map的key和value值的步驟和代碼示例

    在Java中,我們都知道直接交換Map的key和value是不被允許的,因為Map的接口設(shè)計是基于key-value對的,其中key是唯一的,并且是不可變的,所以本文給大家介紹了Java交換map的key和value值的步驟和代碼示例,需要的朋友可以參考下
    2024-09-09
  • Java中的RASP機(jī)制實(shí)現(xiàn)詳解

    Java中的RASP機(jī)制實(shí)現(xiàn)詳解

    這篇文章主要介紹了Java中的RASP實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • 運(yùn)用示例詳細(xì)總結(jié)Java多線程

    運(yùn)用示例詳細(xì)總結(jié)Java多線程

    本文主要講解了Java多線程,該篇幅大量使用代碼以及圖片文字進(jìn)行解析,可以讓小伙伴們了解該方面的知識更加迅速快捷
    2021-08-08

最新評論