1.hash類型的基本介紹
哈希表[之前學過的所有數據結構中,最最重要的]
1.日常開發中,出場頻率非常高.
2.面試中,非常重要的考點,
Redis 自身已經是鍵值對結構了Redis 自身的鍵值對就是通過 哈希 的方式來組織的
把 key 這一層組織完成之后, 到了 value 這一層~~ value 的其中一種類型還可以再是 哈希
哈希類型中的映射關系通常稱為 field-value,?于區分 Redis 整體的鍵值對(key-value),注意這?的 value 是指 field 對應的值,不是鍵(key)對應的值,請注意 value 在不同上下?的作?。
2.hash命令
2.1 hset
HSET key field value [field value ...]
命令有效版本:2.0.0 之后時間復雜度:插??組 field 為 O(1), 插? N 組 field 為 O(N)返回值:添加的字段的個數。
redis> HSET myhash field1 "Hello"(integer) 1redis> HGET myhash field1"Hello"
2.2 hget?
HGET key field
命令有效版本:2.0.0 之后時間復雜度:O(1)返回值:字段對應的值或者 nil。
redis> HSET myhash field1 "foo"(integer) 1redis> HGET myhash field1"foo"redis> HGET myhash field2(nil)
2.3?HEXISTS
HEXISTS key field
命令有效版本:2.0.0 之后
時間復雜度:O(1)返回值:1 表?存在,0 表?不存在。?例:
?redis> HSET myhash field1 "foo"
(integer) 1redis> HEXISTS myhash field1(integer) 1redis> HEXISTS myhash field2(integer) 0
2.4?HDEL
HDEL key field [field ...]
命令有效版本:2.0.0 之后時間復雜度:刪除?個元素為 O(1). 刪除 N 個元素為 O(N).返回值:本次操作刪除的字段個數。
redis> HSET myhash field1 "foo"(integer) 1redis> HDEL myhash field1(integer) 1redis> HDEL myhash field2(integer) 0
- del 刪除的是 key
- hdel 刪除的是 field?
2.5?HKEYS
獲取 hash 中的所有字段。
HKEYS key
命令有效版本:2.0.0 之后時間復雜度:O(N), N 為 field 的個數.返回值:字段列表。
?redis> HSET myhash field1 "Hello"
(integer) 1redis> HSET myhash field2 "World"(integer) 1redis> HKEYS myhash1) "field1"2) "field2"
?2.6?HVALS
HVALS key
命令有效版本:2.0.0 之后時間復雜度:O(N), N 為 field 的個數.返回值:所有的值。
redis> HSET myhash field1 "Hello"(integer) 1redis> HSET myhash field2 "World"(integer) 1redis> HVALS myhash1) "Hello"2) "World"
2.7?HGETALL
HGETALL key
命令有效版本:2.0.0 之后時間復雜度:O(N), N 為 field 的個數.返回值:字段和對應的值。
redis> HSET myhash field1 "Hello"(integer) 1redis> HSET myhash field2 "World"(integer) 1redis> HGETALL myhash1) "field1"2) "Hello"3) "field2"4) "World"
2.8?HMGET
HMGET key field [field ...]
命令有效版本:2.0.0 之后時間復雜度:只查詢?個元素為 O(1), 查詢多個元素為 O(N), N 為查詢元素個數.返回值:字段對應的值或者 nil。
redis> HSET myhash field1 "Hello"(integer) 1redis> HSET myhash field2 "World"(integer) 1redis> HMGET myhash field1 field2 nofield1) "Hello"2) "World"3) (nil)
在使? HGETALL 時,如果哈希元素個數?較多,會存在阻塞 Redis 的可能。如果開發?員只 需要獲取部分 field,可以使? HMGET,如果?定要獲取全部 field,可以嘗試使? HSCAN命令,該命令采?漸進式遍歷哈希類型。【敲一次命令,遍歷一小部分.
再敲一次,再遍歷一小部分時間就是可控的~~化整為零 】
ConcurrentHashMap(線程安全的 哈希表)
這個哈希表在擴容的時候,也是按照化整為零的方式進行的!!
Java 標準庫直接提供了一些線程安全的 集合類
(Java 中也有"容器"這樣的術語,指的是別的了)
2.9?HLEN
HLEN key
命令有效版本:2.0.0 之后時間復雜度:O(1)返回值:字段個數。
示例?
redis> HSET myhash field1 "Hello"(integer) 1redis> HSET myhash field2 "World"(integer) 1redis> HLEN myhash(integer) 2
2.10?HSETNX
HSETNX key field value
命令有效版本:2.0.0 之后時間復雜度:O(1)返回值:1 表?設置成功,0 表?失敗。
redis> HSETNX myhash field "Hello"(integer) 1redis> HSETNX myhash field "World"(integer) 0redis> HGET myhash field"Hello"
2.11?HINCRBY
HINCRBY key field increment
命令有效版本:2.0.0 之后時間復雜度:O(1)返回值:該字段變化之后的值。
redis> HSET myhash field 5(integer) 1redis> HINCRBY myhash field 1(integer) 6redis> HINCRBY myhash field -1(integer) 5redis> HINCRBY myhash field -10(integer) -5
2.12 HINCRBYFLOAT
HINCRBYFLOAT key field increment
命令有效版本:2.6.0 之后時間復雜度:O(1)返回值:該字段變化之后的值。
redis> HSET mykey field 10.50(integer) 1redis> HINCRBYFLOAT mykey field 0.1"10.6"redis> HINCRBYFLOAT mykey field -5"5.6"redis> HSET mykey field 5.0e3(integer) 0redis> HINCRBYFLOAT mykey field 2.0e2"5200" ?
?3.命令小節
命令 | 執?效果 | 時間復雜度 |
hset key field value | 設置值 | O(1) |
hget key field | 獲取值 | O(1) |
hdel key field [field ...] | 刪除 field | O(k), k 是 field個數 |
hlen key | 計算 field 個數 | O(1) |
hgetall key | 獲取所有的 field-value | O(k), k 是 field個數 |
hmget field [field ...] | 批量獲取 field-value | O(k), k 是 field個數 |
hmset field value [field value ...] | 批量獲取 field-value | O(k), k 是 field個數 |
hexists key field | 判斷 field 是否存在 | O(1) |
hkeys key | 獲取所有的 field | O(k), k 是 field個數 |
hvals key | 獲取所有的 value | O(k), k 是 field個數 |
hsetnx key field value | 設置值,但必須在 field 不存在時才能設置成功 | O(1) |
hincrby key field n | 對應 field-value +n | O(1) |
hincrbyfloat key field n | 對應 field-value +n | O(1) |
hstrlen key field | 計算 value 的字符串?度 | O(1) |
?4.hash編碼方式
壓縮:rar, zip, gzip,7....
一些具體的壓縮算法~~
壓縮的本質,是針對數據進行重新編碼.
不同的數據,有不同的特點.結合這些特點,進行精妙的設計重新編碼之后,就能夠縮小體積~
哈希的內部編碼有兩種:? ziplist(壓縮列表):當哈希類型元素個數?于 hash-max-ziplist-entries 配置(默認 512 個)、 同時所有值都?于 hash-max-ziplist-value 配置(默認 64 字節)時,Redis 會使? ziplist 作為哈希的內部實現,ziplist 使?更加緊湊的結構實現多個元素的連續存儲,所以在節省內存???hashtable 更加優秀。 (內部的數據結構更加精妙)? hashtable(哈希表):當哈希類型?法滿? ziplist 的條件時,Redis 會使? hashtable 作為哈希的內部實現,因為此時 ziplist 的讀寫效率會下降,? hashtable 的讀寫時間復雜度為 O(1)。
ziplist 也是同理~~
內部的數據結構也是精心設計的~~
【目的節省內存空間.】
表示一個普通的hash表,可能會浪費一定的空間~~(hash 首先是一個數組~~,數組上有些位置有元素,有些沒有元素)
ziplist 付出的代價,進行讀寫元素,速度是比較慢的,如果元素個數少,慢的并不明顯, 如果元素個數太多了,慢就會雪上加霜,
如果,
1.哈希中的元素個數比較少,使用 ziplist 表示.元素個數比較多,使用 hashtable 來表示2.每個 value 的值長度都比較短,使用 ziplist 表示.如果某個 value 的長度太長了,也會轉換成 hashtable
- hash-max-ziplist-entries 配置(默認 512 個)
- hash-max-ziplist-value 配置(默認 64 字節)
- 這個配置項就是可以寫到 redis.conf 文件中的~~?
5.hash的應用?
5.1 作為緩存
string 也是可以作為緩存使用的.
存儲結構化的數據(類似于 數據庫 表 這樣的結構~~),使用 hash 類型更合適一些~~
上述場景使用 string 類型也能做到,
就需要使用到 json 這樣的數據格式
- 如果使用 string(ison)的格式來表示 Userlnfo萬一只想獲取其中的某個 field, 或者修改某個 field ~~就需要把整個 json 都讀出來, 解析成 對象,操作 field,再重寫轉成 json 字符串,再寫回去~~
- 如果使用 hash 的方式來表示 Userlnfo,就可以使用 field 表示對象的每個屬性(數據表的每個列)此時就可以非常方便的修改/獲取任何一個屬性的值了~~
- 使用 hash 的方式,確實讀寫 field 更直觀高效,但是付出的是空間的代價~~需要控制哈希在 ziplist 和hashtable 兩種內部編碼的轉換,可能會造成內存的較大消耗。
高內聚
把有關聯的東西放在一起,最好能放在指定的地方~~
耦合?
- 兩個模塊/代碼 之間的關聯關系,關聯關系越大,越容易相互影響認為是耦合越大~~
- 追求的是"低耦合,避免"牽一發動全身"這邊一改出 bug,影響到了其他的地方
哈希類型和關系型數據庫有兩點不同之處:
? 哈希類型是稀疏的,而關系型數據庫是完全結構化的,例如哈希類型每個鍵可以有不同的 field,而關系型數據庫?旦添加新的列,所有?都要為其設置值,即使為 null【稀疏更加節省空間】? 關系數據庫可以做復雜的關系查詢,? Redis 去模擬關系型復雜查詢,例如聯表查詢、聚合查詢等基本不可能,維護成本?。