成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot+Redis BitMap 實現簽到與統計功能

開發 前端
我們可以根據 Redis中 提供的 BitMap 位圖功能來實現,每次簽到與未簽到用0 或1 來標識 ,一次存31個數字,只用了2字節 這樣我們就用極小的空間實現了簽到功能。

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

簽到功能,我們可以通過Redis中的 BitMap功能來實現。

一、Redis BitMap 基本用法

BitMap 基本語法、指令

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

圖片圖片

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

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

這樣的壞處,占用內存太大了,極大的消耗內存空間!

我們可以根據 Redis中 提供的 BitMap 位圖功能來實現,每次簽到與未簽到用0 或1 來標識 ,一次存31個數字,只用了2字節 這樣我們就用極小的空間實現了簽到功能。

BitMap 的操作指令:

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

使用 BitMap 完成功能實現

服務器Redis版本采用 6.2。

進入redis查詢 SETBIT 命令

圖片圖片

新增key 進行存儲

圖片圖片

查詢 GETBIT命令

圖片圖片

查看指定坐標的簽到狀態

圖片圖片

查詢 BITFIELD

圖片圖片

無符號查詢

圖片圖片

BITPOS 查詢1 和 0 第一次出現的坐標

圖片圖片

二、SpringBoot 整合 Redis 實現簽到 功能

需求介紹

采用BitMap實現簽到功能

  • 實現簽到接口,將當前用戶當天簽到信息保存到Redis中

思路分析:

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

實現簽到接口,將當前用戶當天簽到信息保存至Redis中

圖片圖片

提示:因為BitMap 底層是基于String數據結構,因此其操作都封裝在字符串操作中了。

圖片圖片

核心源碼

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

接口進行測試

ApiFox進行測試

圖片圖片

查看Redis 數據

圖片圖片

三、SpringBoot 整合Redis 實現 簽到統計功能

問題一:什么叫做連續簽到天數?

從最后一次簽到開始向前統計,直到遇到第一次未簽到為止,計算總的簽到次數,就是連續簽到天數。

圖片圖片

邏輯分析:

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

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

BITFIELD key GET u[dayOfMonth] 0

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

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

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

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

需求:

實現以下接口,統計當前截至當前時間在本月的連續天數。

圖片圖片

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

核心源碼

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. 獲取本月截至今天為止的所有的簽到記錄,返回的是一個十進制的數字 BITFIELD sign:5:202301 GET u3 0
    List<Long> result = stringRedisTemplate.opsForValue().bitField(
        key,
        BitFieldSubCommands.create()
        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
    //沒有任務簽到結果
    if (result == null || result.isEmpty()) {
        return Result.ok(0);
    }
    Long num = result.get(0);
    if (num == null || num == 0) {
        return Result.ok(0);
    }
    //6. 循環遍歷
    int count = 0;
    while (true) {
        //6.1 讓這個數字與1 做與運算,得到數字的最后一個bit位 判斷這個數字是否為0
        if ((num & 1) == 0) {
            //如果為0,簽到結束
            break;
        } else {
            count ++;
        }
        num >>>= 1;
    }
    return Result.ok(count);
}

進行測試

圖片圖片

查看 Redis 變量

圖片圖片

從今天開始,往前查詢 連續簽到的天數,結果為2 測試無誤!

四、關于使用bitmap來解決緩存穿透的方案

回顧緩存穿透:

發起了一個數據庫不存在的,redis里邊也不存在的數據,通常你可以把他看成一個攻擊。

解決方案:

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

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

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

所以我們如何解決呢?

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

圖片圖片

現在的問題是這個主鍵其實并沒有那么短,而是很長的一個 主鍵。

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

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

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

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

圖片圖片

小結

以上就是對 微服務 Spring Boot 整合 Redis BitMap 實現 簽到與統計 的簡單介紹,簽到功能是很常用的,在項目中,是一個不錯的亮點,統計功能也是各大系統中比較重要的功能,簽到完成后,去統計本月的連續 簽到記錄,來給予獎勵,可大大增加用戶對系統的活躍度 技術改變世界!!!

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2024-07-02 11:42:53

SpringRedis自定義

2024-03-27 07:55:58

SpringRedis海量

2020-02-11 16:10:44

Redis分布式鎖Java

2021-05-24 08:58:34

Redis Bitmap 數據統計

2020-04-23 14:35:30

SpringBootRedis數據庫

2025-02-14 09:07:35

2015-04-16 12:27:08

云之家

2025-05-20 09:00:04

SpringGeoHash派單

2025-03-19 08:36:55

2025-03-26 08:43:17

2023-09-26 08:11:22

Spring配置MySQL

2024-03-25 08:32:57

灰度Bitmap平均值

2011-05-10 17:32:36

NFC簽到FoursquareLBS

2023-02-14 07:47:20

SpringBootEhcache

2025-03-04 08:40:28

2025-06-17 08:39:43

2011-01-26 08:59:11

jQueryjavascriptweb

2019-10-23 09:48:46

RedisMySQLMongoDB

2023-10-14 15:29:28

RedisFeed

2022-10-08 10:10:58

內存技術安全
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品色哟哟网站 | 成人一区二区三区在线观看 | 九九久久久久久 | 日韩一区二区三区在线 | 伊人影院99 | 国产午夜在线观看 | 美女精品一区 | www.黄色片视频 | 国产高清免费在线 | av在线免费观看网站 | 91av在线免费观看 | 久草在线高清 | 国产精品久久久久久久久大全 | 久久精品综合 | 在线亚洲电影 | 精品久久国产视频 | 九九热这里只有精品在线观看 | 国产美女一区二区 | 国产精品成人一区二区三区夜夜夜 | 欧美乱码精品一区二区三区 | 黄久久久| 国产高清精品一区 | 91av在线影院 | 一区二区三区欧美 | 在线欧美日韩 | 成人精品国产一区二区4080 | 99re国产视频 | 亚洲第1页 | 亚洲免费人成在线视频观看 | 欧美色999| 久久99久久99精品免视看婷婷 | 日本a网站| 成年人在线观看视频 | 精品综合 | 69堂永久69tangcom | 九九久视频 | 亚洲成人久久久 | 日操操夜操操 | 日韩欧美国产一区二区三区 | 69电影网 | 中国毛片免费 |