最新:Redis持久化——AOF日誌redis
Redis對象——哈希(Hash)cookie
哈希在不少編程語言中都有着很普遍的應用,而在Redis中也是如此,在redis中,哈希類型是指Redis鍵值對中的值自己又是一個鍵值對結構,形如value=[{field1,value1},...{fieldN,valueN}]
,其與Redis字符串對象的區別以下圖所示:
哈希類型的內部編碼有兩種: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哈希對象經常使用命令以下表(點擊命令可查看命令詳細說明)。
命令 | 說明 | 時間複雜度 |
---|---|---|
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裏面的元素 |
Redis哈希對象經常用來緩存一些對象信息,如用戶信息、商品信息、配置信息等。
咱們以用戶信息爲例,它在關係型數據庫中的結構是這樣的
uid | name | age |
---|---|---|
1 | Tom | 15 |
2 | Jerry | 13 |
而使用Redis Hash存儲其結構以下圖:
相比較於使用Redis字符串存儲,其有如下幾個優缺點:
原生字符串每一個屬性一個鍵。
set user:1:name Tom set user:1:age 15
優勢:簡單直觀,每一個屬性都支持更新操做。
缺點:佔用過多的鍵,內存佔用量較大,同時用戶信息內聚性比較差,因此此種方案通常不會在生產環境使用。
序列化字符串後,將用戶信息序列化後用一個鍵保存
set user:1 serialize(userInfo)
優勢:簡化編程,若是合理的使用序列化能夠提升內存的使用效率。
缺點:序列化和反序列化有必定的開銷,同時每次更新屬性都須要把所有數據取出進行反序列化,更新後再序列化到Redis中。
序列化字符串後,將用戶信息序列化後用一個鍵保存
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
不少電商網站都會使用 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
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官方文檔》
關注下方公衆號,回覆「Redis」,可得Redis相關學習資料