redis--黑馬點評--用戶簽到模塊詳解

用戶簽到

假如我們使用一張表來存儲用戶簽到信息,其結構應該如下:

CREATE TABLE `tb_sign` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',`user_id` bigint unsigned NOT NULL COMMENT '用戶id',`year` year NOT NULL COMMENT '簽到的年',`month` tinyint NOT NULL COMMENT '簽到的月',`date` date NOT NULL COMMENT '簽到的日期',`is_backup` tinyint unsigned DEFAULT NULL COMMENT '是否補簽',PRIMARY KEY (`id`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT

假設有1000萬用戶,平均每人每年簽到次數為10次,那么這張表一年的數據量為1億條。還是保守估計,因此,用數據庫表來存儲太過浪費內存空間。

并且每一個用戶簽到一次需要使用(8+8+1+1+3+1)共22字節的內存,并且沒有包括隱藏字段,一個月最多需要600多字節。

因此這種方式既耗內存,數據庫壓力還大。

那有沒有比較好的方法呢?

我們按照月來統計用戶簽到信息,簽到記錄為1,未簽到記錄為0,這樣我們只需要最多31bit就可以表示一個用戶一個月的簽到情況,非常節省空間,這種做法的核心思想就是把每一個比特位對應當月的每一天,形成了映射關系,用0和1表示業務狀態。

這種思路就叫做位圖BitMap)。

而在redis底層是利用String類型數據結構實現BitMap,因此最大上限是512M,轉換為bit則是2^32個bit位。

BitMap用法

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出現的位置

命令演示:

添加

setbit:簽到則為1,不簽到可以不輸入,默認為0

image-20250806220447565

查看redis客戶端:

image-20250806220545220

查詢

image-20250806220836773

BITFIELD

image-20250806221103566

在查詢時 offset指定從哪讀,type指定讀多少bit位,并且還要指定返回的是否帶符號。(因為返回的是十進制,因此要說明是否帶符號,如果帶符號,二進制第一位則為符號位,因此u代表無符號,i代表有符號,一般使用無符號)

舉例說明:

image-20250806221721635

BITPOS

image-20250806221953803

簽到功能

案例實現:簽到功能

需求:實現簽到接口,將當前用戶當天簽到信息保存到redis中

接口請求解析:

說明
請求方式Post
請求路徑/user/login
請求參數
返回值

在請求解析中,我們發現請求參數與返回值都為空,這是因為我們簽到所需的用戶以及當天日期都可以在后端直接獲取,因此不需要前端傳參,也不需要返回值,但如果是補簽功能的話,就需要前端傳遞日期參數了

注意:因為BitMap底層是基于String數據結構,因此其操作也都被封裝在字符串相關操作中了。

key組成:用戶+日期(原因:簽到往往是以月為統計單位的,因此每個用戶每個月的簽到情況放在一個BitMap中,方便統計)

代碼實現:

controller層:

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

Service層:

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

運行效果:

image-20250806224553581

image-20250806231348363

至此簽到功能完成。

簽到統計

簽到統計有很多種:比如統計該月總簽到次數、該月截止今天的連續簽到次數等等,

那么什么叫做連續簽到天數呢?

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

那么如何使用Java代碼實現統計連續簽到天數?

方法1:給每個bit位拼接逗號,然后spit(0),最后一個數組長度就是連續天數,最長的數組就是最長連續天數

方法2:從最后一個比特位開始遍歷,并定義一個計數器,為1則加一,為0則終止。其中有些關鍵問題:

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

在BitMap的指令中:bitfield可以獲取指定范圍內的所有簽到數據,而該指令需要兩個參數,一個是從哪開始,另一個是查多少。因為要得到本月到今天為止的所有簽到數據,因此起始腳標為0,而offset則為日期值,

由此得到指令:bitfield key get u[dayOfMonth] 0

問題2:如何從后往前的遍歷每一個bit位

解答:與1做與運算,就能得到最后一個比特位。隨后在右移一位,下一個bit位就成為了最后一個bit位,隨后同上操作,以此類推,便可以從后向前的遍歷每一個bit位。

至此,思路理順,付諸實踐

案例展示:實現簽到統計功能

需求:實現下面接口,統計當前用戶截止當前時間在本月的連續簽到天數

請求解析:

說明
請求方式GET
請求路徑/user/sign/out
請求參數
返回值連續簽到天數

代碼實現:

Controller層:

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

Service層:

?public Result signCount() {//1.獲取當前登錄用戶Long id ?= UserHolder.getUser().getId();//2.獲取當前日期LocalDateTime now = LocalDateTime.now();//3.拼接keyString keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyy/MM"));String key = USER_SIGN_KEY + id + keySuffix;//4.獲取今天是本月的第幾天int dayOfMouth = now.getDayOfMonth();//5.獲取本月截止今天為止的所有的簽到記錄 返回的是一個十進制的數字 bitfield sign:1:2025/08 get u6 0List<Long> result = stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMouth)).valueAt(0));if (result == null || result.isEmpty()){return Result.ok(0);}Long number = result.get(0);if (number == null || number == 0){return Result.ok(0);}//6.循環遍歷int count = 0;while (true){//6.1讓這個數字與1做與運算,得到數字的最后一個bit位  //判斷bit位是否為0if ((number & 1) == 0) {//如果為0,說明未簽到,結束break;}else {//如果不為0,說明已簽到,計數器加一count++;}//把數字右移一位,拋棄最后一個bit位,繼續下一個bit位的判斷// 將number無符號右移一位,相當于將number除以2,并將結果賦值給numbernumber >>>= 1;}return Result.ok(count);}

效果展示:

image-20250807212259015

至此用戶簽到功能完成

希望對大家有所幫助

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92385.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Shell、Python對比

在 Shell 腳本&#xff08;sh/bash&#xff09; 和 Python 之間選擇時&#xff0c;主要取決于具體的使用場景和需求。以下是兩者的對比分析&#xff0c;幫助你判斷哪種更方便&#xff1a;1. Shell 腳本&#xff08;sh/bash&#xff09;的優勢適用場景系統管理任務&#xff1a;如…

自適應反步控制:理論與設計

自適應反步控制 文章目錄自適應反步控制1. 基本思想A. 第一步B. 第二步1. 基本思想 基于傳統反步法&#xff0c;考慮了系統方程中以線性形式出現的未知參數。核心思想包括參數估計率和控制率。 考慮二階系統&#xff1a; {x˙1x2φ1T(x1)θx˙2uφ2T(x1,x2)θ(1)\begin{cases…

[Oracle] LEAST()函數

LEAST() 是 Oracle 中一個非常有用的函數&#xff0c;用于從一組表達式中返回最小值LEAST()函數會從給定的參數列表中返回最小的值&#xff0c;它與GREATEST()函數正好相反語法格式LEAST(expr1, expr2 [, expr3, ...])參數說明expr1, expr2, ...&#xff1a;要比較的表達式(至少…

SVM算法實戰應用

目錄 用 SVM 實現鳶尾花數據集分類&#xff1a;從代碼到可視化全解析 一、算法原理簡述 二、完整代碼實現 三、代碼解析 1. 導入所需庫 2. 加載并處理數據 3. 劃分訓練集和測試集 4. 訓練 SVM 模型 5. 計算決策邊界參數 6. 生成決策邊界數據 7. 繪制樣本點 8. 繪制…

深度虛值期權合約有什么特點?

本文主要介紹深度虛值期權合約有什么特點&#xff1f;深度虛值期權合約是期權市場中一類特殊且風險收益特征鮮明的合約&#xff0c;其核心特點可歸納為以下六點。深度虛值期權合約有什么特點&#xff1f;一、定義&#xff1a;執行價與標的價差距極大深度虛值期權是指執行價&…

(LeetCode 面試經典 150 題) 86. 分隔鏈表(鏈表+雙指針)

題目&#xff1a;86. 分隔鏈表 思路&#xff1a;雙指針&#xff0c;時間復雜度0(n)。 雙指針來維護小于x的鏈表和不小于x的鏈表即可&#xff0c;后面將兩個鏈表連起來即可。 C版本&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* …

安全掃描:檢測到目標站點存在javascript框架庫漏洞問題(vue)

如果升級Vue版本有限制或者時間比較緊急&#xff0c;可以暫時用下面方式來&#xff0c;規避檢測到目標站點存在javascript框架庫vue漏洞。 在 vue.config.js 中配置: module.exports {configureWebpack: {optimization: {minimizer: [new (require(terser-webpack-plugin))({t…

【性能測試】-2- JMeter工具的使用

一、基礎腳本搭建&#x1f3af; 核心目標&#xff1a;用 JMeter 搭性能測試 “骨架”&#xff08;測試計劃、線程組、取樣器、監聽器&#xff09;&#x1f4cb; 測試計劃&#xff1a;整個測試的 “容器”&#xff0c;所有測試組件都放這里&#x1f9f5; 線程組&#xff1a;模擬…

從零構建桌面寫作軟件的書籍管理系統:Electron + Vue 3 實戰指南

&#x1f4da; 從零構建桌面寫作軟件的書籍管理系統&#xff1a;Electron Vue 3 實戰指南 &#x1f4a1; 本文深入探討了基于 Electron Vue 3 技術棧的桌面寫作軟件中書籍管理系統的設計與實現&#xff0c;涵蓋了書籍的創建、編輯、刪除等核心功能的完整技術方案&#xff0c;…

2025華數杯數學建模A題【 多孔膜光反射性能的優化與控制】原創論文講解(含完整python代碼)

大家好呀&#xff0c;從發布賽題一直到現在&#xff0c;總算完成了2025華數杯數學建模A題【 多孔膜光反射性能的優化與控制】完整的成品論文。本論文可以保證原創&#xff0c;保證高質量。絕不是隨便引用一大堆模型和代碼復制粘貼進來完全沒有應用糊弄人的垃圾半成品論文。A題論…

網絡相關(AI回答)

網管交換機都支持帶tag的以太幀嗎DeepSeek-R1 回答完成深度思考完成 用時24秒&#xff0c;搜索全網20篇資料是的&#xff0c;所有網管交換機都支持處理和轉發帶Tag&#xff08;802.1Q VLAN標簽&#xff09;的以太網幀&#xff0c;這是其核心功能之一。以下是關鍵要點&#xff1…

每日五個pyecharts可視化圖表-bars(5)

探索pyecharts庫中條形圖的高級用法與定制技巧&#xff0c;打造精美數據可視化圖表 在數據可視化中&#xff0c;條形圖是最常用的圖表類型之一。它能夠清晰地展示不同類別的數據對比&#xff0c;幫助我們快速理解數據特征。本文將為您介紹pyecharts庫中條形圖的5種高級用法&…

分布式版本控制工具Git

一.開發中為什么需要Git因為在多人開發中Git可以管理代碼&#xff0c;而且每個人都可以從庫里面下載代碼進行修改&#xff0c;每個人上傳和修改Git都會有記錄&#xff0c;如果出現大錯誤&#xff0c;還可以回退到正常版本。二.Git原理我們首先從代碼庫(Remote)下載代碼到工作區…

OpenAI重磅開源GPT-oss:首款支持商用的AI Agent專屬模型

今日凌晨&#xff0c;OpenAI宣布開源兩款全新大模型——GPT-oss-120B&#xff08;1168億參數&#xff09;與GPT-oss-20B&#xff08;209億參數&#xff09;&#xff0c;成為全球首個支持商業化應用的開放權重推理模型。該模型專為AI智能體&#xff08;Agent&#xff09;設計&am…

【STM32】GPIO的輸入輸出

GPIO是通用的輸入輸出接口&#xff0c;可配置8種輸入模式&#xff0c;輸出模式下可控制端口輸出高低電平&#xff0c;用于點亮LED、控制蜂鳴器、模擬通信協議等&#xff1b;輸入模式下可以讀取端口的高低電平或者電壓&#xff0c;用于讀取按鍵、外接模塊的電平信號、ADC的電壓采…

5分鐘了解OpenCV

在數字化時代&#xff0c;圖像和視頻已經成為信息傳遞的核心載體。從手機拍照的美顏功能到自動駕駛的路況識別&#xff0c;從醫學影像分析到安防監控系統&#xff0c;視覺技術正深刻改變著我們的生活。而在這背后&#xff0c;OpenCV 作為一款強大的開源計算機視覺庫&#xff0c…

Oracle 關閉 impdp任務

Oracle 關閉 impdp任務 執行 impdp system/123456 attachSYS_EXPORT_TABLE_01 執行 stop_jobimmediate

數據結構——鏈表2

1.2 實現單鏈表 在上一篇文章中&#xff0c;單鏈表的實現只有一少部分&#xff0c;這一篇接著來了解單鏈表剩下的接口實現。 SList.h#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h>//定義單鏈表就是定義節點&#xff0c;因為單鏈表…

Windows和Linux應急響應以及IP封堵

目錄 1、Windows入侵排查思路 1.1 檢查系統賬號安全 1.2 檢查異常端口、進程 1.3 檢查啟動項、計劃任務、服務 1.4 檢查系統相關信息 1.5 自動化查殺 1.6 日志分析 系統日志分析 Web 訪問日志 2、Linux 入侵排查思路 2.1 賬號安全 2.1.1、基本使用 2.1.2、入侵排查…

MIT成果登上Nature!液態神經網絡YYDS

2025深度學習發論文&模型漲點之——液態神經網絡液態神經網絡&#xff08;Liquid Neural Networks&#xff0c;LNN&#xff09;是一種受生物神經系統啟發的連續時間遞歸神經網絡&#xff08;RNN&#xff09;&#xff0c;其核心創新在于將靜態神經網絡轉化為由微分方程驅動的…