色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何利用SpringBoot+Redis BitMap實(shí)現(xiàn)簽到與統(tǒng)計(jì)功能?

數(shù)據(jù)分析與開(kāi)發(fā) ? 來(lái)源:CSDN ? 2023-10-25 16:41 ? 次閱讀

引言

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

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

一、Redis BitMap 基本用法

BitMap 基本語(yǔ)法、指令

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

356e90ea-730f-11ee-939d-92fbcf53809c.png

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

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

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

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

BitMap 的操作指令:

SETBIT:向指定位置(offset)存入一個(gè)0或1

GETBIT:獲取指定位置(offset)的bit值

BITCOUNT:統(tǒng)計(jì)BitMap中值為1的bit位的數(shù)量

BITFIELD:操作(查詢、修改、自增)BitMap中bit數(shù)組中的指定位置(offset)的值

BITFIELD_RO:獲取BitMap中bit數(shù)組,并以十進(jìn)制形式返回

BITOP:將多個(gè)BitMap的結(jié)果做位運(yùn)算(與 、或、異或)

BITPOS:查找bit數(shù)組中指定范圍內(nèi)第一個(gè)0或1出現(xiàn)的位置

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

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

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

35858bb0-730f-11ee-939d-92fbcf53809c.png

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

358d90d0-730f-11ee-939d-92fbcf53809c.png

查詢 GETBIT命令

359bdae6-730f-11ee-939d-92fbcf53809c.png

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

35a6d612-730f-11ee-939d-92fbcf53809c.png

查詢 BITFIELD

35b5189e-730f-11ee-939d-92fbcf53809c.png

無(wú)符號(hào)查詢

35be7f06-730f-11ee-939d-92fbcf53809c.png

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

35cc7638-730f-11ee-939d-92fbcf53809c.png

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

需求介紹

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

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

思路分析:

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

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

35d70fb2-730f-11ee-939d-92fbcf53809c.png

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

35e1b368-730f-11ee-939d-92fbcf53809c.png

核心源碼

UserController

@PostMapping("sign")
publicResultsign(){
returnuserService.sign();
}

UserServiceImpl

publicResultsign(){
//1.獲取登錄用戶
LonguserId=UserHolder.getUser().getId();
//2.獲取日期
LocalDateTimenow=LocalDateTime.now();
//3.拼接key
StringkeySuffix=now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
Stringkey=RedisConstants.USER_SIGN_KEY+userId+keySuffix;
//4.獲取今天是本月的第幾天
intdayOfMonth=now.getDayOfMonth();
//5.寫(xiě)入redissetbitkeyoffset1
stringRedisTemplate.opsForValue().setBit(key,dayOfMonth-1,true);
returnResult.ok();
}

接口進(jìn)行測(cè)試

ApiFox進(jìn)行測(cè)試

35ec24a6-730f-11ee-939d-92fbcf53809c.png

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

35f0c25e-730f-11ee-939d-92fbcf53809c.png

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

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

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

35fb3180-730f-11ee-939d-92fbcf53809c.png

邏輯分析:

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

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

BITFIELDkeyGETu[dayOfMonth]0

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

問(wèn)題三:如何從后向前遍歷每個(gè)Bit位?

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

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

需求:

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

3601bcda-730f-11ee-939d-92fbcf53809c.png

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

核心源碼

UserController

@GetMapping("/signCount")
publicResultsignCount(){
returnuserService.signCount();
}

UserServiceImpl

publicResultsignCount(){
//1.獲取登錄用戶
LonguserId=UserHolder.getUser().getId();
//2.獲取日期
LocalDateTimenow=LocalDateTime.now();
//3.拼接key
StringkeySuffix=now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
Stringkey=RedisConstants.USER_SIGN_KEY+userId+keySuffix;
//4.獲取今天是本月的第幾天
intdayOfMonth=now.getDayOfMonth();
//5.獲取本月截至今天為止的所有的簽到記錄,返回的是一個(gè)十進(jìn)制的數(shù)字BITFIELDsign202301GETu30
Listresult=stringRedisTemplate.opsForValue().bitField(
key,
BitFieldSubCommands.create()
.get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
//沒(méi)有任務(wù)簽到結(jié)果
if(result==null||result.isEmpty()){
returnResult.ok(0);
}
Longnum=result.get(0);
if(num==null||num==0){
returnResult.ok(0);
}
//6.循環(huán)遍歷
intcount=0;
while(true){
//6.1讓這個(gè)數(shù)字與1做與運(yùn)算,得到數(shù)字的最后一個(gè)bit位判斷這個(gè)數(shù)字是否為0
if((num&1)==0){
//如果為0,簽到結(jié)束
break;
}else{
count++;
}
num>>>=1;
}
returnResult.ok(count);
}

進(jìn)行測(cè)試

3613f5f8-730f-11ee-939d-92fbcf53809c.png

查看 Redis 變量

3618637c-730f-11ee-939d-92fbcf53809c.png

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

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

回顧緩存穿透:

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

解決方案:

判斷id<0

數(shù)據(jù)庫(kù)為空的話,向redis里邊把這個(gè)空數(shù)據(jù)緩存起來(lái)

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

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

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

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

362735f0-730f-11ee-939d-92fbcf53809c.png

現(xiàn)在的問(wèn)題是這個(gè)主鍵其實(shí)并沒(méi)有那么短,而是很長(zhǎng)的一個(gè) 主鍵

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

所以如果采用以上方案,這個(gè)list也會(huì)很大,所以我們可以使用bitmap來(lái)減少list的存儲(chǔ)空間

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

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

3638de72-730f-11ee-939d-92fbcf53809c.png

圖片

小結(jié)

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






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    804

    瀏覽量

    26530
  • 邏輯分析
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    7980
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    374

    瀏覽量

    10871

原文標(biāo)題:SpringBoot+Redis BitMap 實(shí)現(xiàn)簽到與統(tǒng)計(jì)功能

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Redis實(shí)戰(zhàn)篇-16.用戶簽到-實(shí)現(xiàn)簽到功能

    Redis
    電子學(xué)習(xí)
    發(fā)布于 :2023年01月07日 16:50:46

    Redis有序集合詳細(xì)步驟

    利用Redis Sorted Set實(shí)現(xiàn)排行榜功能
    發(fā)表于 05-21 14:09

    在 Java 中利用 redis 實(shí)現(xiàn)一個(gè)分布式鎖服務(wù)

    在 Java 中利用 redis 實(shí)現(xiàn)一個(gè)分布式鎖服務(wù)
    發(fā)表于 07-05 13:14

    Spring boot中Redis的使用

    【本人禿頂程序員】springboot專(zhuān)輯:Spring boot中Redis的使用
    發(fā)表于 03-27 11:42

    淺析Redis的5種基本數(shù)據(jù)類(lèi)型

    多余的話不多說(shuō),今天給大家?guī)?lái)的是 Redis 中的四種特殊的數(shù)據(jù)結(jié)構(gòu) bitmap,hyperLogLog,bloomFilter,GeoHash 。這四種數(shù)據(jù)結(jié)構(gòu)其實(shí)有點(diǎn)類(lèi)似于算法層面了,比如 GeoHash 其實(shí)就是一個(gè) zset,
    的頭像 發(fā)表于 05-05 23:44 ?2708次閱讀
    淺析<b class='flag-5'>Redis</b>的5種基本數(shù)據(jù)類(lèi)型

    Springboot+redis操作多種實(shí)現(xiàn)

    一、Jedis,Redisson,Lettuce三者的區(qū)別共同點(diǎn):都提供了基于Redis操作的Java API,只是封裝程度,具體實(shí)現(xiàn)稍有不同。 不同點(diǎn): 1.1、Jedis 是Redis的Java
    的頭像 發(fā)表于 09-22 10:48 ?1823次閱讀
    <b class='flag-5'>Springboot+redis</b>操作多種<b class='flag-5'>實(shí)現(xiàn)</b>

    SpringBoot實(shí)現(xiàn)多線程

    SpringBoot實(shí)現(xiàn)多線程
    的頭像 發(fā)表于 01-12 16:59 ?1814次閱讀
    <b class='flag-5'>SpringBoot</b><b class='flag-5'>實(shí)現(xiàn)</b>多線程

    SpringBoot+Redis實(shí)現(xiàn)點(diǎn)贊功能的緩存和定時(shí)持久化(附源碼)

    用戶對(duì)瀏覽內(nèi)容進(jìn)行【點(diǎn)贊/取贊】,并發(fā)送【點(diǎn)贊/取贊】請(qǐng)求到后端,這些信息先存入Redis中緩存,再每隔兩小時(shí)將Redis中的內(nèi)容直接寫(xiě)入數(shù)據(jù)庫(kù)持久化存儲(chǔ)。
    的頭像 發(fā)表于 02-09 16:38 ?4556次閱讀

    Redis實(shí)現(xiàn)限流的三種方式分享

    當(dāng)然,限流有許多種實(shí)現(xiàn)的方式,Redis具有很強(qiáng)大的功能,我用Redis實(shí)踐了三種的實(shí)現(xiàn)方式,可以較為簡(jiǎn)單的
    的頭像 發(fā)表于 02-22 09:52 ?1073次閱讀

    基于SpringBoot+Redis的轉(zhuǎn)盤(pán)抽獎(jiǎng)

    基于SpringBoot+Redis等技術(shù)實(shí)現(xiàn)轉(zhuǎn)盤(pán)抽獎(jiǎng)活動(dòng)項(xiàng)目,含前端、后臺(tái)及數(shù)據(jù)庫(kù)文件
    的頭像 發(fā)表于 02-28 14:24 ?1523次閱讀
    基于<b class='flag-5'>SpringBoot+Redis</b>的轉(zhuǎn)盤(pán)抽獎(jiǎng)

    如何在SpringBoot中解決Redis的緩存穿透等問(wèn)題

    今天給大家介紹一下如何在SpringBoot中解決Redis的緩存穿透、緩存擊穿、緩存雪崩的問(wèn)題。
    的頭像 發(fā)表于 04-28 11:35 ?725次閱讀

    如何用Springboot整合Redis

    本篇文件我們來(lái)介紹如何用Springboot整合Redis。 1、Docker 安裝 Redis 1.1 下載鏡像 docker pull redis: 6 . 2 . 6 1.2 創(chuàng)
    的頭像 發(fā)表于 10-08 14:56 ?581次閱讀
    如何用<b class='flag-5'>Springboot</b>整合<b class='flag-5'>Redis</b>

    SpringBoot AOP + Redis 延時(shí)雙刪功能實(shí)戰(zhàn)

    注意:要知道經(jīng)常修改的數(shù)據(jù)表不適合使用Redis,因?yàn)殡p刪策略執(zhí)行的結(jié)果是把Redis中保存的那條數(shù)據(jù)刪除了,以后的查詢就都會(huì)去查詢數(shù)據(jù)庫(kù)。所以Redis使用的是讀遠(yuǎn)遠(yuǎn)大于改的數(shù)據(jù)緩存。
    的頭像 發(fā)表于 10-13 16:08 ?632次閱讀
    <b class='flag-5'>SpringBoot</b> AOP + <b class='flag-5'>Redis</b> 延時(shí)雙刪<b class='flag-5'>功能</b>實(shí)戰(zhàn)

    一個(gè)注解搞定SpringBoot接口防刷

    技術(shù)要點(diǎn):springboot的基本知識(shí),redis基本操作,
    的頭像 發(fā)表于 11-28 10:46 ?401次閱讀

    Redis工具集的實(shí)現(xiàn)和使用

    Redis 基本上是互聯(lián)網(wǎng)公司必備的工具了,Redis的應(yīng)用場(chǎng)景實(shí)在太多了,但是有很多相似的功能如果每個(gè)項(xiàng)目都要實(shí)現(xiàn)一遍就顯得太麻煩了,所以為了方便,我打算開(kāi)發(fā)一個(gè)基于
    的頭像 發(fā)表于 12-03 17:32 ?1225次閱讀
    <b class='flag-5'>Redis</b>工具集的<b class='flag-5'>實(shí)現(xiàn)</b>和使用
    主站蜘蛛池模板: 花蝴蝶在线高清视频观看免费播放| 超碰免费视频caoporn| 欧美亚洲视频在线二区| 高清国产一区| 亚洲一区二区女搞男| 免费夜里18款禁用软粉色| 动漫美女喷水| 亚洲日韩乱码人人爽人人澡人| 就去色一色| 高H高肉强J短篇NP| 亚洲三级视频| 欧美视频精品一区二区三区| 国产精品久久久久久人妻精品蜜桃 | 国产69精品9999XXXX| 亚洲日韩国产成网站在线| 欧美夜夜噜2017最新| 国产午夜精品片一区二区三区| 最近免费中文字幕大全免费| 秋霞午夜鲁丝片午夜精品久 | 午夜影院一区二区三区| 久久香蕉电影| 贵妇局长的蕾丝乳罩| 伊人久久综合影院首页| 日韩欧美视频一区二区| 黑人性xxx| 啊好深啊别拔就射在里面| 久久re这里视频精品8| 99热6精品视频6| 亚洲av欧美在我| 女同给老师下媚药| 国产一区二区三区四区五在线观看| 97人人添人人澡人人澡人人澡| 我们中文在线观看免费完整版| 伦理片92伦理午夜| 国产精品亚洲精品久久国语| 2020国产成人精品视频人| 偷拍亚洲色自拍| 蜜桃麻豆WWW久久囤产精品免费| 国产精品一区二区在线观看| 97久久超碰中文字幕| 亚洲国产区中文在线观看|