Redis 核心概念、命令詳解與應用實踐:從基礎到分布式集成

目錄

1. 認識 Redis

2. Redis 特性

2.1 操作內存

2.2 速度快

2.3 豐富的功能

2.4 簡單穩定

2.5 客戶端語言多

2.6 持久化

2.7 主從復制

2.8 高可用 和 分布式

2.9 單線程架構

2.9.1 引出單線程模型

2.9.2 單線程快的原因

2.10?Redis 和 MySQL 的特性對比

2.11 Redis 使用場景

3. 分布式系統

3.1 分布式系統的核心概念

3.1.1 應用 (Application) / 系統 (System)

3.1.2 模塊 (Module) / 組件 (Component)?

3.1.3 分布式 (Distributed)

3.1.4 集群 (Cluster)

3.1.5 主 (Master) / 從 (Slave)

3.1.6 中間件 (Middleware)

3.2 分布式系統的由來

4. Redis 常用命令

4.1 KESY

4.2 EXISTS

4.3 DEL

4.4 EXPIRE

4.5 TTL

4.6 鍵過期的機制

4.7 TYPE

4.8 Redis 數據結構和內部編碼

4.9 String 字符串

4.9.1 SET

4.9.2 GET

4.9.3 MGET

4.9.4 MSET

4.9.5 SETNX

4.9.6 INCR

4.9.7 INCRBY

4.9.8 DECR

4.9.9 DECRBY

4.9.10?INCRBYFLOAT

4.9.11 APPEND

4.9.12 GETRANGE

4.9.13 SETRANGE

4.9.14?STRLEN

4.9.15 String 命令小結

4.10 Hash 哈希

4.10.1 HSET

4.10.2 HEGT

4.10.3 HEXISTS

4.10.3 HDEL

4.10.4 HKEYS

4.10.5 HVALS

4.10.6 HGETALL

4.10.7 HMGET

4.10.8 HLEN

4.10.9 HSETNX

4.10.9 HCRBY

4.10.9 HCRBYFLOAT

4.10.10 Hash 命令小結

4.10.11 Hash 應用場景

4.11 List 列表

4.11.1 列表的特點

4.11.2 LPUSH

4.11.3 LPUSHX

4.11.4 PUSH

4.11.5?PUSHX

4.11.6 LRANGE

4.11.7 LPOP

4.11.8 RPOP

4.11.9 LINDEX

4.11.9 LINSERT

4.11.10 LEN

4.11.11 BLPOP

4.11.12 BRPOP

4.11.13?LREM

4.11.14?LTRIM

4.11.15?List 命令小結

4.11.16?List 使用場景

4.12 SET 集合

4.12.1 SADD

4.12.2?SMEMBERS

4.12.3 SISMEMBER

4.12.4 SCARD

4.12.5 SPOP

4.12.6 SMOVE

4.12.7 SREM

4.12.8 SINTER

4.12.9?SINTERSTORE

4.12.10 SUNION

4.12.11?SUNIONSTORE

4.12.12 SDIFF

?4.12.13?SDIFFSTORE

?4.12.14 命令小結

?4.12.15 Set 使用場景

?4.13 Zset 有序集合

?4.13.1 ZADD

?4.13.2 ZCARD

?4.13.3 ZCOUNT

?4.13.4 ZRANGE

?4.13.5 ZREVRANGE

?4.13.6 ZRANGEBYSCORE

?4.13.7 ZPOPMAX

4.13.8?BZPOPMAX

4.13.9 ZPOPMIN

4.13.9 BZPOPMIN

4.13.10 ZRANK

4.13.11 ZSCORE

4.13.12 ZREM

4.13.12 ZREMRANGEBYRANK

4.13.13 ZREMRANGEBYSCORE

4.13.13 ZINCRBY

4.13.13 ZINTERSTORE

4.13.14 ZUNIONSTORE

4.13.15 Zset 命令小結

4.13.16 Zset 使用場景

4.14 漸進式遍歷

4.15 數據庫管理

4.15.1 select

4.15.2 flushdb / flushall

4.16 不常用命令集合

4.16.1 Stream

4.16.2 Geospatial

4.16.3 Hyperloglog

4.16.4 Bitmaps

4.16.5 Bitfields?

5. RESP??

6. Jedis

6.1?引入 Jedis 依賴

6.2 Jedis 命令集

7 Spring Boot 使用 Redis

7.1 配置依賴

7.2 String 類

7.3 List 類

7.3 Hash 類

7.4 Set 類

7.5 Zset 類


1. 認識 Redis

Redis 是一種 基于鍵值對(key - value) 的 NoSQL(Not Only SQL) 數據庫,屬于非關系型數據庫。與很多鍵值對數據庫不同的是,Redis 中 key - value 中 value ,數據類型可以為 string、hash、list、set、zset 等等,因此 Redis 可以? 滿足很多應用場景。

非關系型數據庫:它不依賴固定的表結構,通常以鍵值對、文檔、列族或圖等形式存儲數據,更適合處理大規模、高并發或非結構化數據。

關系型數據庫:比如 MySQL 就是一個典型的關系型數據庫。

2. Redis 特性

2.1 操作內存

Redis 會將所有數據存放在 內存中,所以 Redis 的讀寫性能非常恐怖;此外 Redis 還可以將內存數據 利用快照和日志 的形式保存在硬盤上,所以在發生 類似斷電 的故障時,內存中 Redis 管理的數據不會丟失。

2.2 速度快

(1) Redis 是用 C 語言實現的,“距離” 操作系統更近,執行速度相對會更快。

(2) Redis 使用了單線程,預防了多線程可能產生的競技問題。

Redis 在 6.0 版本引入了多線程機制,但主要也是在 處理網絡和IO,不涉及到數據命令,即命令的執行仍采用了單線程模式。不會產生 多個 進程訪問造成的數據異常現象。

Redis 在執行策略上,核心執行模型基于單線程事件循環,主要依賴 I/O 多路復用技術(如 epoll、kqueue)處理高并發請求。

2.3 豐富的功能

除了 5種 數據結構,Redis 還提供了 許多額外的功能:

(1) 提供了鍵過期功能,可以用來實現緩存

(2) 支持 Lua 腳本功能,可以利用 Lua 創造出新的 Redis 命令。

(3) 提供了簡單的事務功能,能在一定程度上保證事務特性。

(4) 提供了流水線(Pipeline) 功能,這樣客戶端能將 一批 命令 一次性 傳到 Redis,減少了網絡的開銷。

Redis 基于網絡 可以把自己內存中的變量,給別的進程,甚至別的主機進行使用。Redis 在分布式系統中,才能發揮威力。如果 是單機程序,那么定義變量在內存中,是比 Redis 更好的選擇。

2.4 簡單穩定

Redis 的簡單主要體現在三個方面

首先,Redis 的源碼少,早起版本只有 2萬 行左右。3.0 版本以后由于 添加了集群特性,代碼增至 5 萬行左右。其次 Redis 使用單線程模型,使得 Redis 服務器端 和 客戶端的開發變得簡單。最后 Redis 不依賴于操作系統中的類庫,Redis 自己實現了事件處理的相關功能。

分布式系統:由多臺計算機 通過網絡連接,協同完成任務。各節點通常具備獨立計算和存儲能力,通過消息傳遞實現協作。

集群系統:多臺計算機 集中部署在同一局域網內,通過同一管理對外提供服務,節點間共享任務負載,通常用于提供性能或可靠性

關聯性:均通過多臺機器協作提高系統的可用性、擴展性或容錯性。實際場景中常結合部署,例如分布式集群(如Hadoop集群分部署在不同機房)。

2.5 客戶端語言多

Redis 基于 TCP 通信協議,很多編程語言可以很方便的 接入Redis,所以支持 Redis 的客戶端非常多,列入 C、C++、JAVA 等多種語言

2.6 持久化

Redis 提供了兩種 持久化方式:RDB 和 AOF,可以用兩種策略將內存的數據保存在硬盤中,就保證了數據的可持久性

2.7 主從復制

Redis 提供了復制功能,實現了多個相同數據 的 Redis 副本,復制功能是 分布式 Redis 的基礎嗎。

2.8 高可用 和 分布式

Redis 提供了 高可用實現的 Redis 哨兵 (Redis Sentinel),能夠保證 Redis 節點的故障發現和故障自動轉移。也提供了 Redis 集群?(Redis Cluster),是真正的分布式實現,提供了高可用、讀寫和容量的拓展性。

2.9 單線程架構

Redis 使用了單線程架構 來實現高性能內存數據庫服務。我將先通過 多個客戶端命令調用的例子 說明 Redis 單線程命令處理機制,接著分析 Redis 單線程模型性能為什么 如此之高。

2.9.1 引出單線程模型

現在開啟了三個 redis-cli 客戶端同時執行命令

客戶端 1 設置一個字符串鍵值對:
?

127.0.0.1:6379> set hello world

客戶端 2 對 counter 做自增操作:
?

127.0.0.1:6379> incr counter

客戶端 3 對 counter 做自增操作:

127.0.0.1:6379> incr counter

我們知道 Redis 使用的是單線程模型,理論上 這些命令是按照 線性方式執行的,只是原則上 命令的執行順序是不確定的,但是 一定不會有兩條命令被同步執行。兩條 incr 命令無論執行順序,結果一定是 2,這個就是 Redis 的單線程執行模型。

2.9.2 單線程快的原因

通常來說,單線程處理能力要比多線程差,但是 Redis 單線程之所以快,分為一下三個原因。

(1) 純內存訪問,Redis 將所有數據都放在內存中,內存的響應大約 100 納秒,是 Redis 訪問快的重要基礎。

(2) 非阻塞 IO,Redis 使用 epoll 作為 I/O 多路復用技術的實現,加上 Redis 本身的事件處理模型 將 epoll 中的連接、讀寫、關閉都轉為事件,不在網絡 I/O 上浪費過多時間

(3) 單線程 避免了 線程切換和競態產生的消耗。單線程可以簡化數據結構和算法的實現,讓程序模擬更簡單。

(4) Redis 和 mysql 訪問速度對比

? ? ? ? <1> Redis 訪問內存,MySQL?訪問硬盤

? ? ? ? <2> Redis 核心功能 比 MySQL?數據庫核心功能簡單,mysql 在插入、刪除和更新時,具有更復雜的功能支持,也有數據約束性。

????????<3> redis 是單線線程操作,對比多線程減少了不必要的線程競爭開銷

????????<4>處理網絡 IO 時,redis 使用了?epoll 這樣的 IO 多路復用機制

雖然單線程給 Redis 帶來了很多好處,但是 每一個命令 不能執行過長,不然就會造成? Redis 客戶端的阻塞。

2.10?Redis 和 MySQL 的特性對比

說到數據庫,那么我們一定就會想到 MySQL。那么 Redis 和 MySQL 有什么比較明顯的差異呢?

(1) MySQL 數據查詢時 會因為 涉及數據約束等因素,IO查詢次數會涉及多次,而 Redis 的查詢功能 不像 MySQL 那么強大,所以 Redis 查詢速度會更快;

(2) MySQL 儲存數據 在 硬盤,Redis 儲存數據在內存。對于計算機來說,儲存在 內存中的速度 遠遠大于 儲存在硬盤中的速度,大約會快 10萬 倍。

(3) MySQL 儲存在硬盤,所帶來的優勢就是 儲存的空間要很大。而 Redis 儲存在內存中,儲存空間 就要小的很多了。相比擴充 內存 的消費來說,擴充 硬盤的消費 要小的很多。

2.11 Redis 使用場景

redis 是一個基于內存存儲的中間件,訪問速度快,常用于 緩存、實時性數據存儲、會話(session)存儲、消息隊列、排行榜系統、計數器應用、社交網絡、消息隊列系統、?機驗證碼等。

在計算機領域中,有一個"二八原則",具體指的是,20% 的數據 要滿足 80% 的訪問需求。

3. 分布式系統

上述 Redis 介紹中提到過分布式系統,那么什么是分布式系統呢?

3.1 分布式系統的核心概念

3.1.1 應用 (Application) / 系統 (System)

由單個程序 或 一組協同工作的 程序群組成,用于完成特定服務或任務。

3.1.2 模塊 (Module) / 組件 (Component)?

復雜系統中 為了分離職責 而 分離的單元,具有 高內聚性 和 明確功能。

3.1.3 分布式 (Distributed)

系統的模塊部署于 不同的服務器,依賴網絡通信協作。

3.1.4 集群 (Cluster)

多臺服務器上部署同一組件群,共同實現特定目標。邏輯上強調目標一致性。

3.1.5 主 (Master) / 從 (Slave)

集群中分工角色:主節點承擔核心職責(如數據寫入),從節點執行輔助任務(如數據同步)。例如數據庫主庫負責寫操作,從庫同步數據并提供讀服務。

3.1.6 中間件 (Middleware)

一類提供 不同應用程序 相互通信的軟件,即處于不同技術、工具和數據庫之間的橋梁。如 數據庫、緩存、消息隊列等.....。

3.2 分布式系統的由來

(1) 期初用戶訪問量少,沒有對性能、安全等提出很高的要求時,單機架構是合適的。單機架構 簡單,無需專業的運維團隊。

(2) 隨著系統的上線,用戶的訪問量逐步上升,逐漸逼近了硬件資源的極限。面對性能壓力,提出了應用數據分離架構。選擇將應用和數據分離的做法,可以最小代價的提升系統的承載能力。

和單機架構的主要區別在于將數據庫服務獨?部署在同?個數據中?的其他服務器上,應?服務通過 ?絡訪問數據。

(3) 隨著爆款的出現,單臺應用服務器已經無法滿足需求了。解決方案有以下兩條:
? ? ? ? 垂直拓展 / 縱向拓展 Scale Up,通過購買性能更優,價格更高的應用服務器來應對更多流量。優勢在于不需要對系統軟件做調整,缺點就是 硬件性能 不是線性提升,費錢的同時 提升卻不大。

? ? ? ? 水平拓展 / 橫向拓展 Scale Out,通過增加應用層硬件,將用戶流量分配到不同的服務器上,來提升系統的 承載能力。優勢在于 成本低,提升的上限空間大,缺點是 復雜的系統,需要 豐富經驗的 技術團隊維護。

顯然,水平拓展更能解決問題。為了使用水平拓展方案,不得不引入一個新的 組件------負載均衡;負載均衡 是一個專門的做 流量分發的系統組件,流量調度算法有多種,簡單且常見的為以下幾種:

? ? ? ? <1> Round-Robin 輪詢算法:即公平地將請求依次分給不同的應用服務器

? ? ? ? <2> Weight-Round-Robin 輪詢算法:為不同的服務器 賦予不同的 權重

? ? ? ? <3> 哈希散列算法:通過計算用戶的特征值(如 IP 地址) 得到哈希值,根據哈希值結果做分發,優點是確保來自相同用戶的請求總是被分給指定的服務器。

(4) 隨著業務的增長,可以動態擴張服務器數量來緩解壓力。但是現在的架構中,無論拓展多少臺服務器,請求最終都會從數據區 讀寫數據,我們不能像 拓展服務器一樣 拓展數據庫,因為數據庫的 數據有其特殊性。

可以采用的解決方法為,保留一個主要的數據庫作為寫入數據庫,其他的數據庫作為從數據庫。從數據庫所有數據來自 主數據庫,經過同步后,從庫可以維護與主庫一樣的數據,為主庫分擔讀數據的壓力。

(5) 隨著訪問數據量的增加,一些數據的讀取頻率 遠遠大于 其他數據的讀取頻率。我們把 這部分數據稱為 熱點數據,與之對應的是 冷數據。針對 熱數據,為了提升讀取的響應時間,可以增加本地緩存,并在外部增加分布式緩存。

(6) 隨著業務的數據量增大,如果想進一步減少服務器壓力,則可以引入多個數據庫服務器,每個數據庫服務器存儲一個或多個表。 如果其中表過大也可以針對表進行拆分,存儲到不同的數據庫服務器,以上可以稱為"分庫分表",解決存儲空間不足的問題。

微服務:?微服務是一種軟件架構風格,將單一應用程序劃分為一組小型、獨立的服務。每個服務運行在自己的進程中,通過輕量級通信機制(如HTTP/REST或消息隊列)進行交互。微服務通常圍繞業務功能進行組織,可以獨立部署、擴展和維護。為了 精確分工,代碼解耦合。微服務需要網絡通信,比硬盤來說還要慢很多。但是萬兆網卡讀寫速度比硬盤快,唯一的缺點就是 貴。

4. Redis 常用命令

object encoding key ,查看 key 對應的 value 實際的編碼方式

4.1 KESY

通配符模式通配符說明匹配示例不匹配示例
h?llo??匹配1 個任意字符hellohallohxlloheeello(中間 3 個e)、hllo(中間 0 個字符)
h*llo*?匹配0 個或多個任意字符hllo(0 個字符)、heeeello(多個e理論無(*覆蓋所有中間字符數量)
h[ae]llo[ae]?匹配 **a?或?e?中的 1 個 **helloe)、halloahillo(中間i)、hxllo(中間x
h[^e]llo[^e]?匹配非?e?的 1 個字符halloa)、hbllob)、hclloc)…hello(中間e
h[a-b]llo[a-b]?匹配 **a?或?b?中的 1 個 **(按 ASCII 范圍)halloa)、hbllobhcllo(中間c)、hdllo(中間d

語法:

KEYS pattern

時間復雜度 O(N)?

返回值:匹配 pattern 的所有 key

4.2 EXISTS

判斷某個 key 是否存在

語法:

EXISTS key [key....]

時間復雜度O(1)

返回值:key 存在的個數

示例:
?

4.3 DEL

刪除指定的 key

語法:

DEL key [key...]

時間復雜度O(1)

返回值:刪除掉 key 的個數

示例:

4.4 EXPIRE

為指定的 key 添加秒級的過期時間

語法:

EXPIRE key seconds

時間復雜度O(1)

返回值:1 表示設置成功,0 表示設置失敗

示例:

4.5 TTL

獲取指定 key 的過期時間,秒級

時間復雜度O(1)

返回值: 過期時間,-1 表示沒有關聯過時間,-2 表示 key 不存在

語法:

TTL key 

示例:

EXPIRE 和 TTL 命令都有對應的?持毫秒為單位的版本:PEXPIRE 和 PTTL。

IP 協議中的 TTL 不是用時間衡量,而是用次數。

4.6 鍵過期的機制

我們知道 直接遍歷所有的 key 效率非常低,redis 的策略有兩種,定期刪除 和 惰性刪除。

? ? ? ? 定期刪除:Redis 默認每隔 100 毫秒隨機抽取一部分設置了過期時間的鍵,檢查是否過期,如果過期則刪除。這種策略通過分散操作來減少對系統性能的影響,但無法保證所有過期鍵都會被立即清理。

? ? ? ? 惰性刪除:當客戶端嘗試訪問某個鍵時,Redis 會先檢查該鍵是否已過期,如果過期則直接刪除并返回空值。惰性刪除確保只有在鍵被訪問時才會觸發清理操作,節省了不必要的 CPU 開銷,但可能導致大量過期鍵堆積。

除了上述兩種,redis 還提供了多種內存淘汰策略;redis 中沒有采取 定時器 的方式來實現過期 key 刪除。如果有多個 key 過期,也可以基于 優先級隊列或時間輪 實現定時器,來高效/節省 cpu 的前提下來處理多個 key。

4.7 TYPE

返回 key 對應的 數據類型

語法:

TYPE key

時間復雜度O(1)

返回值:value 對應的數據類型,包括 none,string,list,set,zset,hash....等

示例:

4.8 Redis 數據結構和內部編碼

數據結構內部編碼編碼特點 / 設計邏輯適用條件(或觸發轉換的閾值)
stringint存儲整數型值,直接以?long?類型存儲,節省空間、讀寫高效(無需字符串解析)。值可轉為整數(如?"123"),且在 Redis 整數范圍(通常 ±9007199254740992,即?2^53?邊界)。
embstr短字符串專用,內存連續分配(對象頭 + 字符串內容),只讀(修改會轉為?raw)。字符串長度 ≤39 字節(Redis 不同版本可能微調,如早期 ≤39,后續版本可能因內存優化調整),且未被修改過。
raw通用字符串存儲,內存分開分配(對象頭和字符串內容獨立),支持任意長度修改。字符串長度 >39 字節,或?embstr?被修改(如?APPEND?操作)。
hashziplist緊湊的壓縮列表,字段和值依次存儲,適合小數據量,讀寫需遍歷(性能依賴數據量)。字段數量 ≤hash-max-ziplist-entries(默認 512),且字段 / 值長度 ≤hash-max-ziplist-value(默認 64)。
hashtable哈希表結構,字段為鍵、值為哈希節點,支持?O (1) 查找,但內存開銷稍大。字段數量 / 長度超過上述閾值,自動轉為?hashtable(轉換不可逆)。
listziplist壓縮列表存儲,元素按順序排列,適合少量短元素,插入 / 查詢需遍歷。元素數量 ≤list-max-ziplist-entries(默認 512),且元素長度 ≤list-max-ziplist-value(默認 64)。
linkedlist雙向鏈表結構,插入 / 刪除高效(O (1) 定位后操作),但內存開銷大(每個節點存指針)。Redis 3.2 前:元素數量 / 長度超過閾值時轉為?linkedlist
Redis 3.2+:默認用?quicklistziplist?鏈表,兼顧緊湊性和效率)。
setintset整數集合,緊湊數組存儲(按升序排列),通過二分查找,僅支持整數元素。所有元素為整數,且數量 ≤set-max-intset-entries(默認 512)。
hashtable哈希表結構,元素為鍵(值為?null),支持任意類型元素,查找?O(1)存在非整數元素,或數量超過閾值,自動轉為?hashtable(轉換不可逆)。
zsetziplist壓縮列表存儲,元素按分數排序(需手動保證有序插入),適合小數據量,讀寫需遍歷。元素數量 ≤zset-max-ziplist-entries(默認 128),且元素 / 分數長度 ≤zset-max-ziplist-value(默認 64)。
skiplist跳表 + 字典結構(跳表存有序元素,字典存分數映射),支持快速范圍查詢(O(logN))。元素數量 / 長度超過上述閾值,自動轉為?skiplist(轉換不可逆)。

Redis 這樣設計有兩個好處:

(1) 可以改進內部編碼,而對外的數據結構和命令沒有任何影響,開發出更優秀的內部編碼,無需改動外部數據結構和命令。例如 Redis 3.2 在 list 結構中 提供了 quicklist,結合了 ziplist 和 linkedlist 兩者的優勢。

(2) 多種內部編碼實現 可以在不同的場景下發揮各自的優勢,例如 ziplist 比較節省內存,但是在列表元素較多的情況下,性能會下降,這時候 Redis 會根據配置選項 將列表類型內部實現自動轉換為 linkedlist ,整個過程用戶無感知。

quicklist 是一個鏈表,每個元素是一個 ziplist;當set內元素都是int 時,使用 intset。

4.9 String 字符串

字符串類型是 Redis 最基礎的數據類型。Redis 中所周鍵的類型都是字符串類型,而且其他幾種數據結構也都是在字符串類似基礎上構建的。Redis 有五種數據結構,但都是鍵值對中的值。

由于 Redis 內部存儲字符串完全是按照?進制流的形式保存的,所以 Redis 不處理字符集 編碼問題的,客?端傳?的命令中使?的是什么字符集編碼,就存儲什么字符集編碼。

4.9.1 SET

將 string 類型的 value 設置到 key 中。如果 key 之前存在 則覆蓋,無論之前 key 是什么類型。

語法:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

時間復雜度:O(1)

返回值:設置成功返回 OK,如果 SET 制定了 NX 或 XX 條件不滿足,返回 nil

選項參數格式作用描述等效舊命令示例(Redis 命令行)關鍵注意事項
EXEX <seconds>設置 key 的秒級過期時間(TTL)SETEXSET mykey EX 60 "value"過期時間為?60?秒,過期后 key 自動刪除
PXPX <milliseconds>設置 key 的毫秒級過期時間(TTL)PSETEXSET mykey PX 5000 "value"過期時間為?5000?毫秒(即 5 秒)
NXNX(無值參數)僅當 key 不存在時,才執行 SET 操作SETNXSET mykey NX "new-value"若 key 已存在,命令無效果(返回?nil
XXXX(無值參數)僅當 key 存在時,才執行 SET 操作無直接等效(需手動?EXISTS?判斷)SET mykey XX "update-value"若 key 不存在,命令無效果(返回?nil

XX 可以理解為更新選項,NX 可以理解為創建選項

4.9.2 GET

獲取 key 對應的 value,如果 key 不存在,則返回 nil。如果 value 的數據類型不是 string ,會報錯。

語法:

GET key

時間復雜度O(1)

返回值:key 對應的 value,當 key 不存在時 返回 nil

示例:

4.9.3 MGET

一次性獲取多個 key 的值,如果對應的 key 不存在或者對應的數據類型不是 string,返回 nil

語法:

MGET key [key ...]

時間復雜度O(N),N 是 key 的數量

返回值:對應 value 的列表

示例:

4.9.4 MSET

一次性設置多個 key 的值

語法:

MSET key value [key value ...]

時間復雜度:O(N),N 是 key 的數量

返回值:OK

示例:

使? mget / mset 由于可以有效地減少了?絡時間,所以性能相較更?。

4.9.5 SETNX

只允許在 key 不存在的情況下設置 key-value?

語法:

SETNX key value

時間復雜度O(1)

返回值:1 表示設置成功,0 表示設置失敗

示例:

除了 SETNX 還有 SETXX,具體使用規則跟上述規則一樣

4.9.6 INCR

將 key 對應的 string 表示的數字加一,如果 key 不存在,則視 key 對應的 value 為 0。如果 key 對應的? 不是一個整型、string 類型?或 范圍超過了 64 位有符號整型則報錯。

語法:

INCR key

時間復雜度:O(1)

返回值:integer 類型的加完后的數值

示例:

4.9.7 INCRBY

將 key 對應的 string 表示的數字加上對應的值。如果對應的值是負數,則視為減去對應的值。如果 key 不存在,則視 key 對應的 value 值為 0。如果 key 對應的? 不是一個整型、string 類型、或者范圍超過了 64 位有符號整型,則報錯。

語法:

INCRBY key decrement

時間復雜度:O(1)

返回值:integer 類型的加完后的數值

示例:

4.9.8 DECR

將 key 對應的 string 表示的數字減一。如果 key 不存在,則視 key 對應的 value 為 0。如果 key 對應的 不是一個整型、string 類型 或范圍超過了 64 為有符號整型,則報錯。

語法:

DECR key

時間復雜度:O(1)

返回值:integer 類型的減完后的數值

示例:

4.9.9 DECRBY

將 key 對應的 string 表示的數字減去對應的值。如果 key 不存在,則視 key 對應的 value 為 0。如果對應的值是負數,則視為加上對應的值。如果 key 對應的不是一個整型、string 類型 或范圍超過了 64 為有符號整型,則報錯。

語法:

DECRBY key decrement

時間復雜度:O(1)

返回值:integer 類型的減完后的數值

示例:

4.9.10?INCRBYFLOAT

將 key 對應的 string 表示的浮點數加上對應的值。如果對應的值是負數,則視為減去對應的值。如果 key 不存在,則視 key 對應的 value 為 0。如果 key 對應的 不是一個 string 類型 、浮點數 或 整數,則報錯。允許采用科學技術表示浮點數。

語法:

INCRBYFLOAT key increment

時間復雜度:O(1)

返回值:加/減 完之后的數值

示例:

4.9.11 APPEND

如果 key 已經存在并且是一個? string 或者可以轉換成 string 類型的,命令會將 vlaue 追加到原有的 string 的后邊。如果 key 不存在,則效果等同于 SET 命令

語法:

APPEND KEY VALUE

時間復雜度:O(1)

返回值:追加完之后的 string 長度

示例:

4.9.12 GETRANGE

返回 key 對應的 string 的子串,由 start 和 end 確定 (閉區間)。可以使用負數表示倒數,-1 代表隊尾。超過 string 長度 會自動調整成正確的值

語法:

GETRANGE key start end

時間復雜度:O(N),N 為 [start , end] 區間的長度。由于 string 通常比較短,可以視為是 O(1)

返回值:string 類型的子串

示例:

4.9.13 SETRANGE

覆蓋字符串的一部分,從指定的偏移量開始

語法:

SETRANGE key offset value

時間復雜度:O(N),N 為 value 的長度。由于一般給的 value 比較短,通常視為 O(1)

返回值:替換后的 string 長度

示例:

4.9.14?STRLEN

獲取 key 對應的 string 長度。當 key 存放的類型不是 string 時報錯

語法:

STRLEN key

時間復雜度:O(1)

返回值:string 的長度。當 key 不存在時 返回 0

示例:

4.9.15 String 命令小結

命令執行效果時間復雜度
set key value [key value...]設置 key 的值是 valueO (k),k 是鍵個數
get key獲取 key 的值O(1)
del key [key ...]刪除指定的 keyO (k),k 是鍵個數
mset key value [key value ...]批量設置指定的 key 和 valueO (k),k 是鍵個數
mget key [key ...]批量獲取 key 的值O (k),k 是鍵個數
incr key指定的 key 的值 +1O(1)
decr key指定的 key 的值 -1O(1)
incrby key n指定的 key 的值 +nO(1)
decrby key n指定的 key 的值 -nO(1)
incrbyfloat key n指定的 key 的值 +nO(1)
append key value指定的 key 的值追加 valueO(1)
strlen key獲取指定 key 的值的長度O(1)
setrange key offset value覆蓋指定 key 的從 offset 開始的部分值O (n),n 是字符串長度,通常視為 O (1)
getrange key start end獲取指定 key 的從 start 到 end 的部分值O (n),n 是字符串長度,通常視為 O (1)

4.10 Hash 哈希

幾乎所有的主流變成語言都提供了 哈希 (hash) 類型,哈希類型指本身是一個鍵值對結構。Redis 鍵值對和哈希類型二者的關系可以由下圖表示

哈希類型中的映射關系通常被稱為 field-value ,用于區分 Redis 整體的鍵值對 (key-value),注意這里的 value 是指 filed 對應的值,不是鍵 (key) 對應的值。

4.10.1 HSET

設置 hash 中指定的 字段 (field) 的 值 (value)

語法:

HSET key field value [field value ...]

時間復雜度:插入一組 field 為 O(1),插入 N 組 field 為 O(N)

返回值:添加的字段個數

示例:

4.10.2 HEGT

獲取 hash 中指定 field 的值

語法:

HGET key field

時間復雜度:O(1)

返回值:字段對應的值或nil

示例:

4.10.3 HEXISTS

判斷 hash 中是否有指定的 field

語法:

HEXISTS key field

時間復雜度:O(1)

返回值:1 表示存在,0 表示不存在

示例:

4.10.3 HDEL

刪除 hash 中指定的 field

語法:

HDEL key field [field ...]

時間復雜度:刪除一個元素為 O(1),刪除 N 個元素為 O(N)

返回值:本次操作刪除的字段個數

示例:

4.10.4 HKEYS

獲取 hash 中所有的 field

語法:

HKEYS key

時間復雜度:O(N),N 為 field 的個數

返回值:字段列表

示例:

4.10.5 HVALS

獲取 hash 中的所有 value

語法:

HVALS key

時間復雜度:O(N),N 為 field 個數

返回值:所有的值

示例:

4.10.6 HGETALL

獲取 hash 中所有的 field 和所對應的 value

語法:

HGETALL key

時間復雜度:O(N),N 為 field 的個數

返回值:field 和對應的 value

示例:

4.10.7 HMGET

一次獲取 hash 中多個 field 所對應的 value

語法:

HMGET key field [field ...]

時間復雜度:只查詢一個元素為 O(1),查詢N個元素為 O(N)

返回值:字段對應的值或 nil

示例:

4.10.8 HLEN

獲取 hash 中的所有字段的個數

語法:

HLEN key

時間復雜度:O(1)

返回值:field 個數

示例:

4.10.9 HSETNX

在 field 不存在的情況下,設置 hash 中的 field 和所對應的 value

語法:

HSETNX key field value

時間復雜度:O(1)

返回值:1 表示設置成功,0 表示失敗

示例:

4.10.9 HCRBY

將 hash 中 field 對應的 value 值添加指定的值

語法:

HINCRBY key field increment

時間復雜度:O(1)

返回值:該 field 所對應的 value 變化之后的值

示例:

4.10.9 HCRBYFLOAT

HINCRBY 的浮點數版本

語法:

HINCRBYFLOAT key field increment

時間復雜度:O(1)

返回值:該 field 所對應的 value 變化之后的值

示例:

4.10.10 Hash 命令小結

命令執行效果時間復雜度
hset key field value設置值O(1)
hget key field獲取值O(1)
hdel key field [field ...]刪除 fieldO (k),k 是 field 個數
hlen key計算 field 個數O(1)
hgetall key獲取所有的 field-valueO (k),k 是 field 個數
hmget field [field ...]批量獲取 field-value
hmset field value [field value ...]批量獲取 field-valueO (k),k 是 field 個數
hexists key field判斷 field 是否存在O(1)
hkeys key獲取所有的 fieldO (k),k 是 field 個數
hvals key獲取所有的 valueO (k),k 是 field 個數
hsetnx key field value設置值,但必須在 field 不存在時才能設置成功O(1)
hincrby key field n對應 field-value +nO(1)
hincrbyfloat key field n對應 field-value +nO(1)
hstrlen key field計算 value 的字符串長度O(1)

4.10.11 Hash 應用場景

存儲結構化的數據,比如說表的結構,一個 userinfo 里有多個 屬性。 如果要通過 String 存儲,就需要使用 像 Json 這樣的格式。而 Json 這樣的格式 不能單獨操作單一屬性,需要轉化來轉化去,相比于 Redis 能直接修改單一屬性就會增加運行時間。但是 Json 比 Redis 的需要的內存空間要少,因為 Redis 的實現是 Hash 類型,需要大量的 內存空間。

Hash 類型做緩存的優缺點

優點:簡單、直觀、靈活。尤其是針對信息的局部變換或者獲取操作。

缺點:需要控制哈希在 ziplist 和 hashtable 兩種內部編碼的轉換,可能會造成內存的較大消耗。

4.11 List 列表

列表類型是用來存儲多個有序的字符串,列表中的每個字符串被稱為 元素 (element)。在 Redis ,可以對列表兩端插入 (push) 和彈出 (pop)。還可以獲取指定范圍的元素列表,獲取指定索引下標的元素等。Redis 中的 List 可以充當棧和隊列的角色,在實際開發中有很多應用場景。

4.11.1 列表的特點

(1) 列表中的元素是有序的,意味著可以通過索引下標獲取某個元素或某個范圍的元素列表

(2) 區分獲取和刪除的區別, lrem 操作會刪除列表中的元素并且獲取值,但是 lindex 操作只會獲取元素,列表的長度不變

(3) 列表中的元素是允許重復的

4.11.2 LPUSH

講一個或多個元素從左側頭插到 lsit 中

語法:

LPUSH key element [element ...]

時間復雜度:直插入一個元素為 O(1),插入多個元素為?O(N),N 為插入元素個數

返回值:插入后 lsit 的長度

示例:

4.11.3 LPUSHX

在 key 存在時,將一個或多個元素從左側頭插到 lsit 中,不存在則直接返回 0

語法:

LPUSHX key element [element ...]

時間復雜度:只插入一個元素為 O(1),插入 N 個元素為 O(N)。

返回值:插入后 lsit 的長度

示例:

4.11.4 PUSH

將一個或多個元素從右側尾插到 lsit 中

語法:
?

RPUSH key element [element ...]

時間復雜度:只插入一個元素為 O(1),插入 N 個元素為 O(N)。

返回值:插入后 lsit 的長度

示例:

4.11.5?PUSHX

將一個或多個元素從右側尾插到 lsit 中

語法:
?

RPUSHX key element [element ...]

時間復雜度:只插入一個元素為 O(1),插入 N 個元素為 O(N)。

返回值:插入后 lsit 的長度

示例:

4.11.6 LRANGE

獲取 start 到 end 區間的所有元素,閉區間。

語法:

LRANGE key start stop

時間復雜度:O(N)

返回值:指定區間的元素

示例:

4.11.7 LPOP

從 list 左側取出元素(頭刪)

語法:

LPOP key

時間復雜度:O(1)

返回值:取出的元素或 nil

示例:
?

4.11.8 RPOP

從 list 右側取出元素(尾刪)

語法:

RPOP key

時間復雜度:O(1)

返回值:取出的元素或 nil

示例:

4.11.9 LINDEX

獲取從左側樹第 index 位置的元素

語法:

LINDEX key index

時間復雜度:O(N)

返回值:取出的元素或nil

示例:

4.11.9 LINSERT

在特定位置插入元素

語法:

LINSERT key <BEFORE | AFTER> pivot element

時間復雜度:O(N)

返回值:插入后 list 的長度

示例:

4.11.10 LEN

獲取 list 長度

語法:

LLEN key

時間復雜度:O(1)

返回值:list 的長度

示例:

4.11.11 BLPOP

LPOP 的阻塞版本,可以通過 timeout 設置最長等待時間

語法:

BLPOP key [key ...] timeout

時間復雜度:O(1)

返回值:取出的元素或nil

示例:

4.11.12 BRPOP

RPOP 的阻塞版本,可以通過 timeout 設置最長等待時間

語法:

BRPOP key [key ...] timeout

時間復雜度:O(1)

返回值:取出的元素或nil

示例:

4.11.13?LREM

刪除制定個數元素,count 指刪除的個數,element 刪除的元素

語法:

LREM key count element

count > 0? 從左往右找 對應個數的 元素

count < 0 從右往左找 對應個數的 元素

count = 0?刪除所有的 對應的 元素

時間復雜度:O(N),N 為列表總元素

示例:

4.11.14?LTRIM

刪除 start 和 stop 區間之外的所有元素

語法:

LTRIM key start stop

時間復雜度:O(N) ,N 為列表總元素

示例:

4.11.15?List 命令小結

操作類型命令語法時間復雜度說明
添加rpush key value [value ...]O(k) ,k?為新增元素的個數
添加lpush key value [value ...]O(k) ,k?為新增元素的個數
添加linsert key before | after pivot valueO(n) ,n?是?pivot?元素距離列表頭 / 尾的遍歷距離(需遍歷找位置)
查找lrange key start endO(s+n) ,s?是?start?偏移量,n?是?start?到?end?的元素數量
查找lindex key indexO(n) ,n?是目標索引的遍歷偏移量(從表頭 / 尾遍歷到索引)
查找llen keyO (1) (直接讀取內部維護的列表長度,無需遍歷)
刪除lpop keyO (1) (直接移除列表頭元素)
刪除rpop keyO (1) (直接移除列表尾元素)
刪除lrem key count valueO(k) ,k?為列表總元素個數(需遍歷匹配并刪除)
刪除ltrim key start endO(k) ,k?為列表總元素個數(保留范圍、刪除其余元素)
修改lset key index valueO(n) ,n?是目標索引的遍歷偏移量(遍歷到索引后修改)
阻塞操作blpop?/?brpopO (1) (操作本身直接訪問頭尾;阻塞為等待邏輯,不影響復雜度)

4.11.16?List 使用場景

(1) 消息隊列

Redis 可以使用 lpush + brpop 命令組合實現經典的阻塞式生產證-消費者模型列隊。生產者客戶端使用 lpush 從列表左側插入元素,多個消費者客戶端使用 brpop 命令阻塞式的從隊列中“爭搶”隊首元素。通過多個客戶端來保證消費的負載均衡和高可用性

(2) 分頻道的消息隊列

Redis 同樣使用 lpush + brpop 命令,但通過不同的鍵模擬頻道的概念,不同的消費者可以通過 brpop 不同的鍵,實現訂閱不同頻道的理念。

同側存取 (lpush + lpop 或 rpush + rpop) 為棧

異側存取 (lpush + rpop 或 rpush + lpop) 為隊列

現在 redis 內的 list 大多使用 quicklist 結構,相當于?ziplist 和 linkedlist 的結合,整體是一個鏈表,但是鏈表的每個節點都是一個 壓縮列表;每個壓縮列表都不大,把多個壓縮列表通過鏈式結構連接起來。

4.12 SET 集合

集合類型也是保存多個字符串類型的元素的,但和列表類型不同的是,集合中的元素是不能重復 和無序的。Redis 除了支持集合內的增刪改查操作,同時還支持多個集合取交集、并集、差集。

4.12.1 SADD

將一個或多個元素添加到 set 中,重復的元素無法添加到 set 中。

語法:

SADD key member [member ...]

時間復雜度:O(1)

返回值:本次成功添加的元素個數

示例:

4.12.2?SMEMBERS

獲取一個 set 中的所有元素,元素間的順序是無序的

語法:

SMEMBERS key

時間復雜度:O(N)

返回值:所有元素的列表

示例:

4.12.3 SISMEMBER

判斷一個元素在不在 set 中

語法:

SISMEMBER key member

時間復雜度:O(1)

返回值:1 表示在 set 中,0 表示不在 set 中或 key 不存在

示例:
?

4.12.4 SCARD

獲取一個 set 的基數,即 set 中的元素個數

語法:

SCARD key

時間復雜度:O(1)

返回值:set 內的元素個數

示例:
?

4.12.5 SPOP

從 set 中刪除并返回一個或多個元素,注意 set 內元素是無序的,所以取出哪個元素實際上是隨機的。

語法:

SPOP key [count]

時間復雜度:O(N),,N 是 count

返回值:取出的元素

示例:

4.12.6 SMOVE

將一個元素從源 set 取出并放入目標 set 中

語法:

SMOVE source destination member

時間復雜度:O(1)

返回值:1 表示移動成功,0 表示移動失敗

示例:

4.12.7 SREM

將指定的元素從 set 中刪除

語法:

SREM key member [member ...]

時間復雜度:O(N),N 是要刪除的元素個數

返回值:本次操作刪除的元素個數

示例:
?

4.12.8 SINTER

獲取給定 set 的交集中的元素

語法:

SINTER key [key ...]

時間復雜度:O(N*M),N 是最小的集合元素個數,M 是最大的集合元素個數

返回值:交集的元素

示例

4.12.9?SINTERSTORE

獲取給定 set 的交集中的元素 并保存到目標 set 中

語法:

SINTERSTORE destination key [key ...]

時間復雜度:O(N*M),N 是最小的集合元素個數,M 是最大的集合元素個數

返回值:交集的元素個數

示例:

4.12.10 SUNION

獲取給定 set 的并集中的元素

語法:

SUNION key [key ...]

時間復雜度:O(N),N 給定的所有集合的總的元素個數

返回值:并集的元素

示例:

4.12.11?SUNIONSTORE

獲取給定 set 的并集中的元素 儲存到 新的集合中

語法:

SUNIONSTORE destination key [key ...]

時間復雜度:O(N),N 給定的所有集合的總的元素個數

返回值:并集的元素個數

示例:

4.12.12 SDIFF

獲取給定 set 的差集中的元素

語法:

SDIFF key [key ...]

時間復雜度:O(N),N 給定的所有的集合的總的元素個數

返回值:差集的元素

示例:

?4.12.13?SDIFFSTORE

獲取給定 set 的差集中的元素,存儲到 目標集合中。

語法:

SDIFFSTORE destination key [key ...]

時間復雜度:O(N),N 給定的所有的集合的總的元素個數

返回值:差集的元素的個數

示例:

?4.12.14 命令小結

命令語法時間復雜度說明
sadd key element [element ...]O(k)?,k?是新增元素的總個數(哈希表批量添加,與元素數量線性相關)
srem key element [element ...]O(k)?,k?是待移除元素的個數(哈希表批量刪除,與元素數量線性相關)
scard keyO(1)?(直接讀取集合內部維護的元素數量計數器,無需遍歷)
sismember key elementO(1)?(哈希表特性支持快速存在性判斷,類似字典查鍵)
srandmember key [count]O(n)?,n?是?count(需隨機選取 / 處理?count?個元素,與數量線性相關)
spop key [count]O(n)?,n?是?count(刪除操作需修改哈希表結構,與處理元素數量線性相關)
smembers keyO(k)?,k?是集合總元素個數(需遍歷哈希表所有元素,返回全量結果)
sinter key [key ...]?/?sinterstoreO(m * k)?:
-?k?是參與交集的集合中元素最少的集合的大小(以最小集合為基準遍歷);
-?m?是參與交集的鍵的數量(多集合對比需多輪遍歷)
sunion key [key ...]?/?sunionstoreO(k)?,k?是所有參與并集的集合的元素個數總和(合并去重需遍歷全量元素)
sdiff key [key ...]?/?sdiffstoreO(k)?,k?是所有參與差集的集合的元素個數總和(遍歷對比全量元素找差異)

?4.12.15 Set 使用場景

集合類型比較典型的使用場景式 標簽。例如 A 用戶對娛樂感興趣,B 用戶對歷史感興趣。有了 用戶的 標簽,就可以 推送 用戶喜歡的內容,并且 將標簽相同的用戶聚集起來。也可以給用戶推薦 好友相似度高的賬號。

(1) 計算 UV 每個用戶訪問服務器,都會產生一個 uv,但是同一個用戶多次訪問,不會使 uv 增加,需要 uv 按照用戶進行去重,上述去重過程,就可以使用 set 來實現。

(2) 給用戶添加標簽

(3) 給標簽添加用戶

(4) 刪除用戶下的標簽

(5) 刪除標簽下的用戶

(6) 計算用戶的共同興趣標簽

?4.13 Zset 有序集合

有序集合相對于字符串、列表、哈希、集合來說,Zset 保留了集合不能有重復成員的特點,但與集合不同的是,有序集合中的每個元素 都有一個唯一的浮點數的分數 (score) 與之相關。有序集合按照分數的大小排列,按照分數 升序排列,即 從小到大排列。zset 中的 member 要求仍是唯一,但是 score 可以相同。

列表、集合、有序集合三者的異同點:

數據結構類型是否允許重復元素有序性特點有序依據(排序規則)典型應用場景舉例
列表(List)物理索引有序索引下標(按插入 / 操作維護順序)時間軸(如動態朋友圈)、消息隊列(任務排隊)
集合(Set)完全無序無(僅保證元素唯一性)標簽系統(用戶興趣標簽去重)、社交關系(共同好友交集)
有序集合(Sorted Set)邏輯分數有序分數(score,支持自定義規則)排行榜(游戲段位、積分排名)、帶權重的社交場景(影響力排序)

?4.13.1 ZADD

添加或更新指定的元素及關聯的分數到 zset 中,分數應該符合 double 類型,+inf/-inf 作為正負極限也是合法的。

使用 zset 時,跳表可以使查詢的時間復雜度變到 O(logN)。

ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
選項作用描述
XX僅僅用于更新已經存在的元素,不會添加新元素
NX僅用于添加新元素,不會更新已經存在的元素
CH默認情況下,ZADD 返回的是本次添加的元素個數,指定此選項后,返回結果會包含本次更新的元素個數
INCR效果類似 ZINCRBY,將元素的分數加上指定分數,且此時僅能指定一個元素和對應分數

時間復雜度:O(logN)

返回值:本次添加成功的元素個數

示例:

?4.13.2 ZCARD

獲取一個 zset 的基數,即 zset 中的元素個數

語法:

ZCARD key

時間復雜度:O(1)

返回值:zset 內的元素個數

示例:

?4.13.3 ZCOUNT

返回分數在 min 和 max 之間的元素個數,默認情況下 閉區間,可以通過“(”排除

語法:

ZCOUNT key min max

時間復雜度:O(logN)

返回值:滿足條件的元素列表個數

示例:

?4.13.4 ZRANGE

返回指定區間里的元素,分數按照升序排列,帶上 WITHSCORES 可以吧分數也返回,閉區間。

語法:

ZRANGE key start stop [WITHSCORES]

時間復雜度:O(log(N)+M)

O(log(N)+M) 因為只需要查找到一個 start,然后挨個去刪除就行 。

返回值:區間內的元素列表

示例:

?4.13.5 ZREVRANGE

返回指定區間里的元素,分數降序排列,帶上 WITHSCORES 可以把分數也返回,閉區間。

語法:

ZREVRANGE key start stop [WITHSCORES]

時間復雜度:O(log(N)+M)

返回值:區間內的元素列表

示例:

?4.13.6 ZRANGEBYSCORE

返回分數在 min 和 max 之間的元素,默認情況下閉區間,可以通過“(”排除

語法:

ZRANGEBYSCORE key min max [WITHSCORES]

時間復雜度:O(log(N)+M)

返回值:區間內的元素列表

示例:

?4.13.7 ZPOPMAX

刪除并返回分數最高的 count 個元素

語法:

ZPOPMAX key [count]

時間復雜度:O(log(N)*M)

返回值:分數和元素列表

示例:

4.13.8?BZPOPMAX

ZPOPMAX 的阻塞版本,可以通過 timeout 設置阻塞的最長時間。

語法:

BZPOPMAX key [key ...] timeout

時間復雜度:O(log(N))

返回值:元素列表

示例:

4.13.9 ZPOPMIN

刪除并返回分數最低的 count 個元素

語法:

ZPOPMIN key [count]

時間復雜度:O(log(N)*M)

返回值:分數和元素列表

示例:

4.13.9 BZPOPMIN

ZPOPMIN?的阻塞版本,可以通過 timeout 設置阻塞的最長時間

語法:

BZPOPMIN key [key...] timeout

時間復雜度:O(log(N)*M)

返回值:元素列表

示例:

4.13.10 ZRANK

返回指定元素的排名,從左往右數

語法:

ZRANK key member

時間復雜度:O(log(N))

返回值:排名

示例:

4.13.10 ZREVRANK

返回指定元素的排名,從右往左數

時間復雜度:O(log(N))

返回值:排名

示例:

4.13.11 ZSCORE

返回指定元素分數

語法:

ZSCORE key member

時間復雜度:O(1)

返回值:分數

示例:

4.13.12 ZREM

刪除指定的元素

語法:

ZREM key member [member ...]

時間復雜度:O(log(N)*M)

返回值:本次操作刪除的元素個數

示例:

4.13.12 ZREMRANGEBYRANK

刪除指定范圍內的元素,閉區間

語法:

ZREMRANGEBYRANK key start stop

時間復雜度:O(log(N)+M)

返回值:本次操作刪除的元素個數

示例:

4.13.13 ZREMRANGEBYSCORE

按照分數刪除指定范圍的元素,閉區間。

時間復雜度:O(log(N)+M)

返回值:本次操作刪除的元素個數

示例:

4.13.13 ZINCRBY

未指定的元素相關聯的分數添加指定的分值

語法:

ZINCRBY key increment member

時間復雜度:O(log(N))

返回值:增加后元素的分數

示例:

4.13.13 ZINTERSTORE

求出給定有序集合中元素的交集并保存進目標有序集合中,在合并過程中以元素為單位進行合并,元 素對應的分數按照不同的聚合方式和權重得到新的分數。

語法:

ZINTERSTORE destination numkeys key [key ....] [ WEIGHTS weight [weight.....]] [AGGREGATE <SUM | MIN | MAX>]
命令元素含義說明
numkeys整數,指定參與交集計算的有序集合總數量(需與后續?key?列表的長度嚴格一致
key [key ...]參與交集計算的有序集合鍵列表(需提供?numkeys?個鍵,如?key1 key2 key3?,數量與?numkeys?匹配)
WEIGHTS weight [weight ...]可選參數,為每個輸入集合設置分數權重(默認全為?1?)。元素分數會先乘以對應權重,再參與交集計算;權重數量需與?numkeys?一致
AGGREGATE <SUM|MIN|MAX>可選參數,指定交集結果中元素分數的聚合規則
-?SUM(默認):將所有集合對應元素的「分數 × 權重」求和
-?MIN:取所有集合對應元素的「分數 × 權重」最小值
-?MAX:取所有集合對應元素的「分數 × 權重」最大值

有序集合中 member 才是交集的參考量, score 只是一個排序的工具,如果 member 相同, score 不同,aggregate 有三種策略來決定?交集的 score,aggregate 不寫默認 SUM 策略

時間復雜度 O(N*K)+O(M*log(M)),近似來看相當于 O(M*logM)

返回值:目標集合中的元素個數

示例:

4.13.14 ZUNIONSTORE

求出給定有序集合中元素的并集并保存進目標有序集合中,在合并過程中以元素為單位進行合并,元 素對應的分數按照不同的聚合方式和權重得到新的分數。

語法:

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]

時間復雜度 O(N*K)+O(M*log(M)),近似來看相當于 O(M*logM)

返回值:目標集合中的元素個數

示例:

4.13.15 Zset 命令小結

命令語法功能說明時間復雜度
zadd key score member [score member ...]向有序集合添加 / 更新成員(按?score?排序,支持批量操作)O(k · log(n))
-?k:新增 / 更新的成員數量;
-?n:當前有序集合的總元素數
zcard key獲取有序集合總成員數量(cardinality,即元素總數)O(1)?(直接讀取內部計數器)
zscore key member查詢指定成員的分數(score)O(1)?(哈希表直接定位成員)
zrank key member
zrevrank key member
查詢成員的正序排名(按?score?升序) /?逆序排名(按?score?降序)O(log(n))
-?n:當前有序集合的總元素數(跳表查找位置)
zrem key member [member ...]從有序集合刪除一個 / 多個成員O(k · log(n))
-?k:刪除的成員數量;
-?n:當前有序集合的總元素數
zincrby key increment member給指定成員增加分數(按增量調整排序,支持分數動態更新)O(log(n))
-?n:當前有序集合的總元素數(跳表查找并更新分數)
zrange key start end [withscores]
zrevrange key start end [withscores]
索引范圍獲取成員(正序 / 逆序,支持帶分數返回)O(k + log(n))
-?k:獲取的成員數量;
-?n:當前有序集合的總元素數(跳表定位范圍 + 遍歷元素)
zrangebyscore key min max [withscores]
zrevrangebyscore key max min [withscores]
分數范圍獲取成員(正序 / 逆序,支持帶分數返回)O(k + log(n))
-?k:獲取的成員數量;
-?n:當前有序集合的總元素數(跳表定位分數區間 + 遍歷元素)
zcount key min max統計分數范圍內的成員數量(無需返回成員,僅計數)O(log(n))
-?n:當前有序集合的總元素數(跳表定位區間后直接計數)
zremrangebyrank key start end排名范圍刪除成員(根據正序排名區間刪除)O(k + log(n))
-?k:刪除的成員數量;
-?n:當前有序集合的總元素數(跳表定位范圍 + 刪除元素)
zremrangebyscore key min max分數范圍刪除成員(根據分數區間刪除)O(k + log(n))
-?k:刪除的成員數量;
-?n:當前有序集合的總元素數(跳表定位區間 + 刪除元素)
zinterstore destination numkeys key [key ...]計算多有序集合的交集,結果存入新鍵(支持權重、聚合規則)O(n · k) + O(m · log(m))
-?n:輸入集合中元素最少的集合的大小
-?k:輸入集合的數量(多集合對比次數);
-?m:目標集合的元素數(跳表構建結果)
zunionstore destination numkeys key [key ...]計算多有序集合的并集,結果存入新鍵(支持權重、聚合規則)O(n) + O(m · log(m))
-?n:所有輸入集合的元素總數(合并去重遍歷次數);
-?m:目標集合的元素數(跳表構建結果)

4.13.16 Zset 使用場景

有序集合比較典型的使用場景就是排行榜系統,榜單的維度可能是多方面的:按照時間、閱讀量 等。

4.14 漸進式遍歷

Redis 使用 scan 命令進行漸進式遍歷鍵,進而解決直接使用 keys 獲取鍵時可能出現的阻塞問題。每次 scan 命令的時間復雜度是 O(1) ,但是要完整的遍歷所有鍵,需要多次執行 scan。

首次 scan 從0 開始,當 sacn 返回的下次位置為 0 時,遍歷結束。

語法:

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

時間復雜度:O(1)

返回值:下一次 scan 的游標 (cursor) 以及本次 得到的鍵

示例:

(1) count 可以指定一次遍歷的個數,不是一個連續遞增的整數。

(2) 漸進式遍歷 不會在服務器存儲 任何的狀態信息,隨時可以終止,不會對服務器產生任何的副作用

(3) count 要獲取的個數,默認是10,此處的 count 只是 給 redis 服務器一個提示,會差但不會很差很多。

(4) 漸進性遍歷 scan 雖然解決了阻塞的問題,但如果在遍歷期間鍵有所變化(增刪改),可能會導致遍歷時鍵的重復遍歷或遺漏。

thousand -- KB

million 百萬 -- MB兆

billion 十億--- GB

4.15 數據庫管理

Redis 提供了幾個面向 Redis 數據庫的操作,分別是 dbsize、select、flushdb、flushall 命令。

4.15.1 select

可以通過 select 切換數據庫

語法:

select dbIndex

許多關系型數據庫,例如 MySQL 支持在一個實例下有多個數據庫,但是與關系型數據庫用字符來區分不同,Redis 用數字 進行? 數據庫的區分。Redis 默認配置中有 16 個數據庫,不能添加也不能刪除,默認處于 0 號數據庫。

Redis 雖然支持多數據庫,但不建議使用。更好的做法 是維護多個? Redis 實例,而不是在一個 Redis 實例中維護多數據庫。無論是否有多個數據庫,Redis 都是使用單線程模型,彼此之間還是需要排隊等待命令執行。

4.15.2 flushdb / flushall

flushdb / flushall 命令用于清除數據庫,區別在于 flushdb 只清除當前數據庫,flushall 會清除所有數據庫。

4.16 不常用命令集合

4.16.1 Stream

Stream 是 Redis 為消息隊列場景設計的結構,支持阻塞讀取,解決了 List 作為隊列時的諸多局限(如無法持久化消息狀態、無消費確認機制等),因此可以視為 List 阻塞隊列的 “增強升級版本”。

Stream 的阻塞讀取特性能實現 “事件驅動” 的效果 —— 消費者可以阻塞等待新消息(事件),當消息(事件)到達時,阻塞被喚醒,進而觸發后續處理邏輯(類似 “回調”),符合事件傳播 “按需觸發” 的特點。

4.16.2 Geospatial

Redis Geospatial 用于存儲地理位置的經緯度坐標(格式為 精度 維度 成員名),并提供了基于坐標的范圍查詢能力,包括:

(1) 半徑查詢:根據指定坐標(或已存成員)為中心,查找指定半徑內的所有成員(支持單位:米、千米、英里、英尺);

(2) 矩形區域查詢:根據指定的矩形范圍(左上角和右下角坐標),查找區域內的所有成員;

(3) 額外支持距離計算:計算兩個已存坐標之間的直線距離(同樣支持多單位)。

4.16.3 Hyperloglog

Hyperloglog 用來估算(存在誤差)集合中的元素個數,不存元素內容,只是計數效果。

在統計 UV 的場景中 Set 能精確存儲元素、精確計數、支持獲取具體元素,但內存隨元素數量線性增長(比如 1 億個 UUID,Set 可能需要幾十 GB);而 HyperLogLog 完全不存元素,12KB 固定空間就能估算上億元素的基數,但無法獲取任何具體元素,且結果是估算值。因此,HyperLogLog 適合 “只需要知道‘有多少個不同的’,不需要知道‘具體是哪些’” 的場景(如 UV、獨立 IP 統計)。

4.16.4 Bitmaps

使用 bit 位來表示整數,每個 bit 對應一個元素,值為?1?表示 “存在 / 有效”,0?表示 “不存在 / 無效”。位圖本質上,還是一個集合。屬于是 set 類型針對 整數的 特化版本

4.16.5 Bitfields?

在編程語言(如 C)中,位域是結構體成員的 “精細化內存控制” 語法
通過 int a : 8; 這類寫法,強制指定成員占用的?bit 位數(而非默認的字節對齊),實現?精準位操作 + 極致空間壓縮(比如用 8bit 存狀態,而非 1 字節)。

5. RESP??

RESP 是?Redis Serialization Protocol(Redis 序列化協議)的縮寫,是 Redis 客戶端與服務器之間標準的通信協議,用于規范命令的發送和響應的格式。它是 Redis 能高效跨語言交互的核心基礎,設計目標是簡單易實現、人類可讀、支持多種數據類型

傳輸層基于 TCP ,但是不合 TCP 強耦合;請求和相應之間的通信模型 是一問一答的形式,客戶端給服務器發送一個請求,服務器給客戶端發送一個響應。

數據類型前綴標識格式示例(以?SET key value?命令的響應為例)
簡單字符串(simple string)+服務器返回成功響應時使用,如?+OK\r\n\r\n?是換行符,作為結束標志)
錯誤(Error)-命令執行失敗時返回,如?-ERR wrong number of arguments\r\n(包含錯誤信息)
整數(Integer):用于返回整數結果,如?INCR key?命令的響應?:1\r\n(表示自增后的值為 1)
批量字符串(bulk string)$用于傳輸二進制安全的字符串(支持包含特殊字符),格式為?$長度\r\n內容\r\n,如?GET key?響應?$5\r\nvalue\r\n(長度為 5 的字符串 "value")
數組(Array)*客戶端發送命令、服務器返回列表 / 集合等多元素結果時使用,格式為?*元素數量\r\n[元素1]\r\n[元素2]...。例如客戶端發送?SET key value?時,實際傳輸的是?*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n(3 個元素:命令名、key、value)

客戶端以 bulk string 數組形式? 發送 redis 命令給服務器;simple string (以 + 開頭) 只能傳輸文本,bulk string (以 $ 開頭)可以傳輸二進制

6. Jedis

Java 操作 redis 的客戶端有很多,其中最知名的是 jedis,創建 maven 項目,把 jedis 的依賴拷貝到 pom.xml 中。

6.1?引入 Jedis 依賴

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.2</version>
</dependency>

6.2 Jedis 命令集

由于 Jedis 與 Redis 客戶端操作風格區別并不大,以下集中演示常用命令:

public class Test {public static void main(String[] args) {JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");try (Jedis jedis = jedisPool.getResource()) {//set gerjedis.set("key1", "value1");jedis.get("key1");//exists deljedis.exists("key1");jedis.del("key1");//keysSet<String> keys = jedis.keys("*");//setex ttljedis.setex("key", 60, "value");long ttl = jedis.ttl("key");System.out.println(ttl);//typejedis.set("key1", "value");System.out.println(jedis.type("key1"));//mset megtjedis.mset("key1", "value1", "key2", "value2", "key3", "value3");List<String> values = jedis.mget("key1", "key2", "key3");System.out.println(values);//appendjedis.append("key", "aaa");String value = jedis.get("key");//getrange setrangeString value1 = jedis.getrange("key", 1, 4);System.out.println(value1);jedis.setrange("key", 0, "xyz");System.out.println(value1);//setnxlong n = jedis.setnx("key", "value");System.out.println(n);//psetexjedis.psetex("key", 1000, "value");long ttl1 = jedis.pttl("key");System.out.println(ttl1);//incr decrjedis.incr("key");System.out.println(jedis.get("key"));jedis.decr("key");System.out.println(jedis.get("key"));//incrby decrbyjedis.incrBy("key", 10);System.out.println(jedis.get("key"));jedis.decrBy("key", 5);System.out.println(jedis.get("key"));//lpush lpoplong n1 = jedis.lpush("key", "1", "2", "3", "4");System.out.println(n1);String value2 = jedis.lpop("key");System.out.println(value2);//rpush rpoplong n3 = jedis.rpush("key", "1", "2", "3", "4");System.out.println(n3);String value3 = jedis.rpop("key");System.out.println(value3);//lrangeList<String> value4 = jedis.lrange("key", 1, 3);System.out.println(value4);//blpopList<String> value5 = jedis.blpop(0, "key");System.out.println(value5);//brpopList<String> value6 = jedis.brpop(0, "key");System.out.println(value6);//lidexString value7 = jedis.lindex("key", 2);System.out.println(value7);//insertjedis.linsert("key", ListPosition.BEFORE, "c", "100");//llenlong n2 = jedis.llen("key");//hset hgetjedis.hset("key", "name", "zhangsan");jedis.hset("key", "age", "20");//hexists hedlboolean ok = jedis.hexists("key", "name");System.out.println(ok);jedis.hdel("key", "name");//hkeys hvalsSet<String> keys1 = jedis.hkeys("key");System.out.println(keys1);List<String> values2 = jedis.hvals("key");System.out.println(values2);//hmgetList<String> values3 = jedis.hmget("key", "name", "age");System.out.println(values3);//hlenlong n4 = jedis.hlen("key");System.out.println(n4);//hincrby hincrbyfloatlong n6 = jedis.hincrBy("key", "age", 10);System.out.println(n6);double dn = jedis.hincrByFloat("key", "age", 0.5);System.out.println(dn);//sadd smembersjedis.sadd("key", "aaa", "bbb", "ccc");Set<String> members = jedis.smembers("key");System.out.println(members);//srem sismemebrboolean ok1 = jedis.sismember("key", "aaa");System.out.println(ok1);long n11 = jedis.srem("key", "aaa", "bbb");System.out.println(n11);//scardlong n12 = jedis.scard("key");System.out.println(n12);//sinterSet<String> results = jedis.sinter("key1", "key2");System.out.println(results);//sunionSet<String> results1 = jedis.sunion("key1", "key2");System.out.println(results1);//sdffSet<String> results2 = jedis.sdiff("key1", "key2");System.out.println(results2);//zadd zrangejedis.zadd("key", 70, "zhangsan");List<String> members1 = jedis.zrange("key", 0, 4);System.out.println(members1);//zrem zcardlong n13 = jedis.zcard("key");System.out.println(n13);n = jedis.zrem("key", "zhangsan");System.out.println(n);//zcountlong n = jedis.zcount("key", 92, 98);System.out.println(n);//zpopmax zpopminTuple tuple = jedis.zpopmax("key");System.out.println(tuple);tuple = jedis.zpopmin("key");System.out.println(tuple);//zranklong n15 = jedis.zrank("key", "zhangsan");System.out.println(n15);//zscoredouble score = jedis.zscore("key", "zhangsan");System.out.println(score);//zincrbydouble n16 = jedis.zincrby("key", 10, "zhangsan");System.out.println(n16);//zinterstorelong n17 = jedis.zinterstore("key3", "key1", "key2");System.out.println(n17);//zunionstorelong n18 = jedis.zunionstore("key3", "key1", "key2");System.out.println(n18);}}

7 Spring Boot 使用 Redis

7.1 配置依賴

spring:redis:host: 127.0.0.1port: 8888

由于 Spring Boot 對 Redis 進行了進一步的封裝,我們需要從 redisTemplate 中獲取方法。下述將簡單的介紹?Spring Boot 中如何使用 Redis 提供的各種類。

7.2 String 類

@GetMapping("/testString")
@ResponseBody
public String testString() {redisTemplate.opsForValue().set("key", "value");String value = redisTemplate.opsForValue().get("key");System.out.println(value);redisTemplate.delete("key");return "OK"
}

7.3 List 類

@GetMapping("/testList")
@ResponseBody
public String testList() {redisTemplate.opsForList().leftPush("key", "a");redisTemplate.opsForList().leftPushAll("key", "b", "c", "d");List<String> values = redisTemplate.opsForList().range("key", 1, 2);System.out.println(values);redisTemplate.delete("key");return "OK";
}

7.3 Hash 類

@GetMapping("/testHashmap")
@ResponseBody
public String testHashmap() {redisTemplate.opsForHash().put("key", "name", "zhangsan");String value = (String) redisTemplate.opsForHash().get("key", "name");System.out.println(value);redisTemplate.opsForHash().delete("key", "name");boolean ok = redisTemplate.opsForHash().hasKey("key", "name");System.out.println(ok);redisTemplate.delete("key");return "OK";
}

7.4 Set 類

@GetMapping("/testSet")
@ResponseBody
public String testSet() {redisTemplate.opsForSet().add("key", "aaa", "bbb", "ccc");boolean ok = redisTemplate.opsForSet().isMember("key", "aaa");System.out.println(ok);redisTemplate.opsForSet().remove("key", "aaa");long n = redisTemplate.opsForSet().size("key");System.out.println(n);redisTemplate.delete("key");return "OK";
}

7.5 Zset 類

@GetMapping("/testZSet")
@ResponseBody
public String testZSet() {redisTemplate.opsForZSet().add("key", "呂布", 100);redisTemplate.opsForZSet().add("key", "趙云", 98);redisTemplate.opsForZSet().add("key", "典?", 95);Set<String> values = redisTemplate.opsForZSet().range("key", 0, 2);System.out.println(values);long n = redisTemplate.opsForZSet().count("key", 95, 100);System.out.println(n);redisTemplate.delete("key");return "OK";
}

如果覺得對你有幫助的話,請給博主一鍵三連吧,這對我真的很重要

(>人<;) 求你了~
(???ω???) 拜托啦~
(≧?≦)ノ 求求你啦~
(?_?) 真的求你了…
(;へ:) 行行好吧~

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

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

相關文章

【Day 18】Linux-DNS解析

目錄 一、DNS概念 1、概念和作用 2、域名解析類型 3、 軟件與服務 4、DNS核心概念 區域 記錄 5、查詢類型 6、分層結構 二、DNS操作 配置本機為DNS內網解析服務器 &#xff08;1&#xff09;修改主配置文件 &#xff08;2&#xff09;添加區域 正向解析區域&#xff1a; …

Python 中 OpenCV (cv2) 安裝與使用介紹

Python 中 OpenCV (cv2) 安裝與使用詳細指南 OpenCV (Open Source Computer Vision Library) 是計算機視覺領域最流行的庫之一。Python 通過 cv2 模塊提供 OpenCV 的接口。 一、安裝 OpenCV 方法 1&#xff1a;基礎安裝&#xff08;推薦&#xff09; # 安裝核心包&#xff0…

微軟WSUS替代方案

微軟WSUS事件回顧2025年7月10日&#xff0c;微軟最新確認Windows Server Update Services&#xff08;WSUS&#xff09;出現了問題&#xff0c;導致IT管理員無法正常同步和部署Windows更新。WSUS是允許管理員根據策略配置&#xff0c;將更新推送到特定計算機&#xff0c;并優化…

Minio 分布式集群安裝配置

目錄創建 mkdir -p /opt/minio/run && mkdir -p /etc/minio && mkdir -p /indata/disk_0/minio/datarun&#xff1a;啟動腳本及二進制文件目錄/etc/minio&#xff1a;配置文件目錄data&#xff1a;數據存儲目錄下載 minio wget https://dl.min.io/server/minio…

Spring Boot + ShardingSphere 實現分庫分表 + 讀寫分離實戰

&#x1f680; Spring Boot ShardingSphere 實現分庫分表 讀寫分離&#xff08;涵蓋99%真實場景&#xff09; &#x1f3f7;? 標簽&#xff1a;ShardingSphere、分庫分表、讀寫分離、MySQL 主從、Spring Boot 實戰 分庫分表 vs 讀寫分離 vs 主從配置與數據庫高可用架構區別 …

將普通用戶添加到 Docker 用戶組

這樣可以避免每次使用 Docker 命令時都需要 sudo。以下是具體步驟&#xff1a;1. 創建 Docker 用戶組&#xff08;如果尚未存在&#xff09; 默認情況下&#xff0c;安裝 Docker 時會自動創建 docker 用戶組。可以通過以下命令檢查&#xff1a; groupadd docker&#xff08;如果…

Scrapy(一):輕松爬取圖片網站內容?

目錄 一、CrawlSpider 簡介? 二、實戰案例&#xff1a;圖片網站爬取? 三、代碼解析&#xff1a;核心組件詳解? 類定義&#xff1a; 2.核心屬性&#xff1a;? 3.爬取規則&#xff08;Rules&#xff09;&#xff1a;? 4.數據提取方法&#xff08;parse_item&#xff09;…

使用 systemd 的原生功能來實現 Redis 的自動監控和重啟,而不是依賴額外的腳本最佳實踐方案

使用 systemd 的原生功能來實現 Redis 的自動監控和重啟&#xff0c;而不是依賴額外的腳本最佳實踐方案方案 1&#xff1a;配置 systemd 服務文件&#xff08;推薦&#xff09;1. 檢查/創建 Redis 的 systemd 服務文件2. 配置關鍵參數&#xff08;覆蓋配置示例&#xff09;3. 重…

Eclipse 代碼模板

Eclipse 代碼模板 引言 Eclipse 作為一款功能強大的集成開發環境&#xff08;IDE&#xff09;&#xff0c;深受廣大開發者的喜愛。在編程過程中&#xff0c;使用代碼模板可以大大提高開發效率&#xff0c;減少重復勞動。本文將詳細介紹 Eclipse 代碼模板的配置、使用方法以及一…

輸電線路防外破聲光預警裝置 | 防山火/防釣魚/防施工安全警示系統

在輸電網絡的安全保障中&#xff0c;外力破壞是一個不容忽視的問題&#xff0c;各類隱患可能對電力系統造成嚴重影響。TLKS-PMG-WP 輸電線路聲光防外破警示裝置在應對這類挑戰時&#xff0c;有著獨特的技術表現&#xff0c;下面從功能和技術參數兩方面進行詳細介紹。核心功能解…

STM32——STM32CubeMX

總&#xff1a;STM32——學習總綱 一、簡介 注意&#xff0c;非邏輯代碼。 可兼容不同系列的STM32Cube固件包。 STM32Cube前置知識鏈接&#xff1a; STM32——HAL庫 不可過多依賴&#xff0c;此工具只針對STM32芯片&#xff0c;類似英飛凌芯片無法配置。主要用于參考。 二、安…

Java NIO 核心原理與秋招高頻面試題解析

一、NIO 概述Java NIO&#xff08;New I/O 或 Non-blocking I/O&#xff09;是 Java 1.4 引入的一套全新 I/O API&#xff0c;位于 java.nio 包下。NIO 提供了與傳統 BIO&#xff08;Blocking I/O&#xff09;完全不同的 I/O 處理方式&#xff0c;通過非阻塞模式、緩沖區&#…

vue3+element-plus,el-popover實現篩選彈窗的方法

實現一個篩選框&#xff0c;點擊篩選按鈕出現彈窗&#xff0c;彈窗內有選擇框/輸入框/單選框等等&#xff0c;底部有重置/確定兩個按鈕。需求&#xff1a;點擊篩選外部其他位置可以關閉彈窗&#xff0c;關閉彈窗后已編輯的數據不保存&#xff0c;點擊確定按鈕關閉彈窗&#xff…

python每日一題 貪心算法練習

在一條環路上有 n 個加油站&#xff0c;其中第 i 個加油站有汽油 gas[i] 升。你有一輛油箱容量無限的的汽車&#xff0c;從第 i 個加油站開往第 i1 個加油站需要消耗汽油 cost[i] 升。你從其中的一個加油站出發&#xff0c;開始時油箱為空。給定兩個整數數組 gas 和 cost &…

Python + Pika RabbitMQ集群壓測完整方案

一、最近搭建了個rabbitmq集群 三個磁盤節點&#xff0c;上生產環境之前想做個壓測&#xff0c;測試下穩定性&#xff0c;參考Deepseek做了如下測試方案二、核心代碼實現&#xff1a; 配置文件 (config.py) import os RABBITMQ_NODES [amqp://admin:123456192.168.0.175:8101,…

【第7話:相機模型3】自動駕駛IPM圖像投影拼接技術詳解及代碼示例

IPM圖像投影拼接技術詳解 IPM&#xff08;逆透視映射&#xff09;圖像投影拼接技術是一種在計算機視覺中廣泛應用的圖像處理方法&#xff0c;主要用于將多個透視視圖的圖像轉換為鳥瞰視圖并拼接成一個無縫的大場景圖像。該技術特別適用于自動駕駛、機器人導航和監控系統等領域&…

【測試工程思考】測試自動化基礎能力建設

1 回顧 傳統軟件研發體系下定義的軟件測試是從用戶視角設計的。測試是試圖窮盡用戶行為的工程&#xff0c;從測試用例&#xff08;use case&#xff09;的英文定義就可見一般。測試的邏輯資產就是用自然語言去描述用戶的操作行為或路徑。 但隨著軟件工程向分布式架構和敏捷交付…

進階向:AI聊天機器人(NLP+DeepSeek API)

什么是AI聊天機器人? AI聊天機器人是一種通過自然語言處理(NLP)技術模擬人類對話的智能程序系統。其核心是建立在機器學習算法和大型語言模型基礎上的對話引擎,能夠理解用戶的自然語言輸入,分析語境和意圖,并生成符合上下文的相關回復。 這類機器人系統通常包含以下幾個…

一個C#的段子

猜猜按鈕的結果是啥。 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } public static bool flag true; privat…

使用 gptqmodel 量化 Qwen3-Coder-30B-A3B-Instruct

代碼部分 : quantize_qwen3_coder_30b_a3b_instruct_gptq.py import os########## 環境變量設置 ########## # 當前可用的 CUDA 編號 os.environ["CUDA_VISIBLE_DEVICES"] "1" # GPU 顯存資源片段優化 os.environ["PYTORCH_CUDA_ALLOC_CONF"] …