Redis對象——哈希(Hash)

系列文章

最新:Redis持久化——如何選擇合適的持久化方式html

最新:Redis持久化——AOF日誌redis

最新:Redis持久化——內存快照(RDB)數據庫

一文回顧Redis五大對象(數據類型)編程

Redis對象——有序集合(ZSet)c#

Redis對象——集合(Set)瀏覽器

Redis對象——列表(List)緩存

Redis對象——哈希(Hash)cookie

Redis數據結構——quicklist數據結構

Redis對象——字符串運維

Redis對象——Redis對象系統簡介

Redis數據結構——壓縮列表

Redis數據結構——整數集合

Redis數據結構——跳躍表

Redis數據結構——字典

Redis數據結構——鏈表

Redis數據結構——簡單動態字符串SDS

哈希在不少編程語言中都有着很普遍的應用,而在Redis中也是如此,在redis中,哈希類型是指Redis鍵值對中的值自己又是一個鍵值對結構,形如value=[{field1,value1},...{fieldN,valueN}],其與Redis字符串對象的區別以下圖所示:

Redis-Hash

1、內部編碼

    哈希類型的內部編碼有兩種:ziplist(壓縮列表),hashtable(哈希表)。只有當存儲的數據量比較小的狀況下,Redis 才使用壓縮列表來實現字典類型。具體須要知足兩個條件:

  • 當哈希類型元素個數小於hash-max-ziplist-entries配置(默認512個)

  • 全部值都小於hash-max-ziplist-value配置(默認64字節)
    ziplist使用更加緊湊的結構實現多個元素的連續存儲,因此在節省內存方面比hashtable更加優秀。當哈希類型沒法知足ziplist的條件時,Redis會使用hashtable做爲哈希的內部實現,由於此時ziplist的讀寫效率會降低,而hashtable的讀寫時間複雜度爲O(1)。
    有關ziplist和hashtable這兩種redis底層數據結構的具體實現能夠參考個人另外兩篇文章。

    Redis數據結構——壓縮列表

    Redis數據結構——字典

2、經常使用命令

Redis哈希對象經常使用命令以下表(點擊命令可查看命令詳細說明)。

命令 說明 時間複雜度
HDEL key field [field ...] 刪除一個或多個Hash的field O(N) N是被刪除的字段數量。
HEXISTS key field 判斷field是否存在於hash中 O(1)
HGET key field 獲取hash中field的值 O(1)
HGETALL key 從hash中讀取所有的域和值 O(N) N是Hash的長度
HINCRBY key field increment 將hash中指定域的值增長給定的數字 O(1)
HINCRBYFLOAT key field increment 將hash中指定域的值增長給定的浮點數 O(1)
HKEYS key 獲取hash的全部字段 O(N) N是Hash的長度
HLEN key 獲取hash裏全部字段的數量 O(1)
HMGET key field [field ...] 獲取hash裏面指定字段的值 O(N) N是請求的字段數
HMSET key field value [field value ...] 設置hash字段值 O(N) N是設置的字段數
HSET key field value 設置hash裏面一個字段的值 O(1)
HSETNX key field value 設置hash的一個字段,只有當這個字段不存在時有效 O(1)
HSTRLEN key field 獲取hash裏面指定field的長度 O(1)
HVALS key 得到hash的全部值 O(N) N是Hash的長度
HSCAN key cursor [MATCH pattern] [COUNT count] 迭代hash裏面的元素

3、適用場景

3.1 存儲對象

​ Redis哈希對象經常用來緩存一些對象信息,如用戶信息、商品信息、配置信息等。

咱們以用戶信息爲例,它在關係型數據庫中的結構是這樣的

uid name age
1 Tom 15
2 Jerry 13

而使用Redis Hash存儲其結構以下圖:

相比較於使用Redis字符串存儲,其有如下幾個優缺點:

  1. 原生字符串每一個屬性一個鍵。

    set user:1:name Tom
    set user:1:age 15

    優勢:簡單直觀,每一個屬性都支持更新操做。
    缺點:佔用過多的鍵,內存佔用量較大,同時用戶信息內聚性比較差,因此此種方案通常不會在生產環境使用。

  2. 序列化字符串後,將用戶信息序列化後用一個鍵保存

    set user:1 serialize(userInfo)

    優勢:簡化編程,若是合理的使用序列化能夠提升內存的使用效率。
    缺點:序列化和反序列化有必定的開銷,同時每次更新屬性都須要把所有數據取出進行反序列化,更新後再序列化到Redis中。

  3. 序列化字符串後,將用戶信息序列化後用一個鍵保存

    hmset user:1 name Tom age 15

    優勢:簡單直觀,若是使用合理能夠減小內存空間的使用。
    缺點:要控制哈希在ziplist和hashtable兩種內部編碼的轉換,hashtable會消耗更多內存。

此外,咱們曾經在作配置中心繫統的時候,使用Hash來緩存每一個應用的配置信息,其在數據庫中的數據結構大體以下表

AppId SettingKey SettingValue
10001 AppName myblog
10001 Version 1.0
10002 AppName admin site

在使用Redis Hash進行存儲的時候

新增或更新一個配置項

127.0.0.1:6379> HSET 10001 AppName myblog
(integer) 1

獲取一個配置項

127.0.0.1:6379> HGET 10001 AppName 
"myblog"

刪除一個配置項

127.0.0.1:6379> HDEL 10001 AppName
(integer) 1

3.2 購物車

    不少電商網站都會使用 cookie實現購物車,也就是將整個購物車都存儲到 cookie裏面。這種作法的一大優勢:無須對數據庫進行寫入就能夠實現購物車功能,這種方式大大提升了購物車的性能,而缺點則是程序須要從新解析和驗證( validate) cookie,確保cookie的格式正確,而且包含的商品都是真正可購買的商品。cookie購物車還有一個缺點:由於瀏覽器每次發送請求都會連 cookie一塊兒發送,因此若是購物車cookie的體積比較大,那麼請求發送和處理的速度可能會有所下降。

    購物車的定義很是簡單:咱們以每一個用戶的用戶ID(或者CookieId)做爲Redis的Key,每一個用戶的購物車都是一個哈希表,這個哈希表存儲了商品ID與商品訂購數量之間的映射。在商品的訂購數量出現變化時,咱們操做Redis哈希對購物車進行更新:

若是用戶訂購某件商品的數量大於0,那麼程序會將這件商品的ID以及用戶訂購該商品的數量添加到散列裏面。

//用戶1 商品1 數量1
127.0.0.1:6379> HSET uid:1 pid:1 1
(integer) 1 //返回值0表明改field在哈希表中不存在,爲新增的field

若是用戶購買的商品已經存在於散列裏面,那麼新的訂購數量會覆蓋已有的訂購數量;

//用戶1 商品1 數量5
127.0.0.1:6379> HSET uid:1 pid:1 5
(integer) 0 //返回值0表明改field在哈希表中已經存在

相反地,若是用戶訂購某件商品的數量不大於0,那麼程序將從散列裏面移除該條目。

//用戶1 商品1
127.0.0.1:6379> HDEL uid:1 pid:2
(integer) 1

3.3 計數器

    Redis 哈希表做爲計數器的使用也很是普遍。它經常被用在記錄網站每一天、一月、一年的訪問數量。每一次訪問,咱們在對應的field上自增1

//記錄個人
127.0.0.1:6379> HINCRBY MyBlog  202001 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog  202001 1
(integer) 2
127.0.0.1:6379> HINCRBY MyBlog  202002 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog  202002 1
(integer) 2

也常常被用在記錄商品的好評數量,差評數量上

127.0.0.1:6379> HINCRBY pid:1  Good 1
(integer) 1
127.0.0.1:6379> HINCRBY pid:1  Good 1
(integer) 2
127.0.0.1:6379> HINCRBY pid:1  bad  1
(integer) 1

也能夠實時記錄當天的在線的人數。

//有人登錄
127.0.0.1:6379> HINCRBY MySite  20200310 1
(integer) 1
//有人登錄
127.0.0.1:6379> HINCRBY MySite  20200310 1
(integer) 2
//有人登出
127.0.0.1:6379> HINCRBY MySite  20200310 -1
(integer) 1

小結

本篇文章咱們總結了Redis 哈希對象的內部實現、經常使用命令以及經常使用的一些場景,那麼你們在項目中對Redis哈希對象的使用都有哪些場景呢,歡迎在評論區給我留言和分享,我會第一時間反饋!咱們共同窗習與進步!

參考

《Redis設計與實現》

《Redis開發與運維》

《Redis官方文檔》

-----END-----

關注下方公衆號,回覆「Redis」,可得Redis相關學習資料

相關文章
相關標籤/搜索