咱們知道Redis是目前很是主流的KV數據庫,它因高性能的讀寫能力而著稱,其實還有另一個優點,就是Redis提供了更加豐富的數據類型,這使得Redis有着更加普遍的使用場景。那Redis提供給用戶的有哪些數據類型呢?主要有:string(字符串)、List(列表)、Set(集合)、Hash(哈希)、Zset(有序集合)、HyperLogLogs(計算基數用的一種數據結構)、Streams(Redis 5.0提供一種建模日誌用的全新數據結構)。java
須要注意的是這裏說的數據類型是指Redis值的數據類型,而Redis鍵的類型老是string。mysql
本文主要詳解一下前5種,也就是最經常使用的5種數據類型。剩下兩種可上Redis官網(redis.io)自行了解下。另外,Redis已是目前Java程序員面試必問內容,而 「Redis有哪些數據類型?」
更是面試官張口就來的基礎問題。若是連這第一問都過不了,那基本上Redis這塊已經涼涼了。程序員
redis的字符串類型,能夠存儲字符串、整數或者浮點數。若是存儲的是整數或者浮點數,還能執行自增或者自減操做。面試
而且redis的string類型是二進制安全的,它能夠包含任何數據,好比一個序列化的對象、一個圖片字節流等。不過存儲大小是由上限的-512Mredis
這裏解釋下二進制安全的含義:簡單的來講,就是字符串不是根據某種特殊的標誌位來(C語言的\0)解析的,不管輸入的是什麼,總能保證輸出是處理的原始輸入而不是根據某種特殊格式來處理。spring
答案是Sds (Simple Dynamic String,簡單動態字符串),Redis底層定義了本身的一種數據結構。(簡單瞭解下)sql
typedef char *sds; struct sdshdr { // buf 已佔用長度 int len; // buf 剩餘可用長度 int free; // 實際保存字符串數據的地方 char buf[]; };
基礎set、get、del命令及示例數據庫
get keyname
獲取存儲在給定鍵中的值
set keyname value
設置存儲唉給定鍵中的值
del keyname
刪除存儲在給定鍵中的值(通用命令,適用於全部類型)安全
127.0.0.1:6379> set happy today OK 127.0.0.1:6379> get happy "today" 127.0.0.1:6379> del happy (integer) 1 127.0.0.1:6379> get happy (nil) 127.0.0.1:6379>
自增和自減命令springboot
incr keyname
將鍵存儲的值加1
decr kename
將鍵存儲的是減1
incrby keyname amount
將鍵存儲的值加上整數amount
decrby keyname amount
將鍵存儲的值減去整數amount
incrbyfloat keyname amount
將鍵存儲的值加上浮點數amount
127.0.0.1:6379> set number 1 OK 127.0.0.1:6379> get number "1" 127.0.0.1:6379> incr number (integer) 2 127.0.0.1:6379> get number "2" 127.0.0.1:6379> decr number (integer) 1 127.0.0.1:6379> get number "1" 127.0.0.1:6379> incrby number 3 (integer) 4 127.0.0.1:6379> get number "4" 127.0.0.1:6379> decrby number 2 (integer) 2 127.0.0.1:6379> get number "2" 127.0.0.1:6379> incrbyfloat number 1.23 "3.23" 127.0.0.1:6379> get number "3.23"
子串和二進制位命令
append keyname value
追加value值到指定字符串末尾
getrange keyname start end
獲取start到end範圍的全部字符組成的子串,包括start和end在內
setrange keyname offset value
從偏移量 offset 開始, 用 value 參數覆寫(overwrite)鍵 keyname 儲存的字符串值。
getbit keyname offset
對 keyname 所儲存的字符串值,獲取指定偏移量上的位(bit)。
setbit keyname offset value
對 keyname 所儲存的字符串值,設置或清除指定偏移量上的位(bit)。
注意redis的索引以0爲開始
127.0.0.1:6379> get hello "world" 127.0.0.1:6379> append hello ,java (integer) 10 127.0.0.1:6379> get hello "world,java" 127.0.0.1:6379> getrange hello 2 5 "rld," 127.0.0.1:6379> setrange hello 6 redis (integer) 11 127.0.0.1:6379> get hello "world,redis" 127.0.0.1:6379> 127.0.0.1:6379> setbit bitstr 100 1 (integer) 0 127.0.0.1:6379> getbit bitstr 100 (integer) 1 127.0.0.1:6379> get bitstr "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b" 127.0.0.1:6379>
其餘幾個重要的命令
setnx key value
只在鍵 key 不存在的狀況下, 將鍵 key 的值設置爲 value;若鍵 key 已經存在, 則 SETNX 命令不作任何動做。
setex key seconds value
將鍵 key 的值設置爲 value , 並將鍵 key 的生存時間設置爲 seconds 秒鐘。若是鍵 key 已經存在, 那麼 SETEX 命令將覆蓋已有的值。
說明一下:
127.0.0.1:6379> exists mark (integer) 0 127.0.0.1:6379> setnx mark abcd (integer) 1 127.0.0.1:6379> setnx mark defg (integer) 0 127.0.0.1:6379> get mark "abcd" 127.0.0.1:6379> setex cachekey 20 ak98 OK 127.0.0.1:6379> get cachekey "ak98" 127.0.0.1:6379> ttl cachekey (integer) 2
Redis的列表類型和許多程序語言中的列表類型相似,能夠有序地存儲多個字符串
。
支持從列表的左端和右端推入或彈出元素。Redis列表的底層實現是壓縮列表(redis內容本身實現的數據結構)和雙端鏈表。看下圖
圖片來自《Redis 設計與實現》
lpush key value [value...]
將一個或者多個value值插入列表的表頭。若是 key 不存在,會建立一個空列表並執行 LPUSH 操做。當 key 存在但不是列表類型時,返回一個錯誤。
執行 LPUSH 命令後,會返回列表的長度。
127.0.0.1:6379> lpush listkey a (integer) 1 127.0.0.1:6379> lpush listkey a b c (integer) 4 127.0.0.1:6379> lrange listkey 0 -1 1) "c" 2) "b" 3) "a" 4) "a" 127.0.0.1:6379>
LPOP key
從列表的左端彈出一個值,並返回被彈出的值
127.0.0.1:6379> lrange listkey 0 -1 1) "c" 2) "b" 3) "a" 4) "a" 127.0.0.1:6379> lpop listkey "c" 127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379>
lrange key start end
獲取列表key在給定start到end範圍上的全部元素值。
0表示第一個元素,-1表示最後一個元素。
127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379> lrange listkey 0 1 1) "b" 2) "a" 127.0.0.1:6379>
lindex key index
獲取列表在給定index位置上的單個元素值。
能夠是-1,表明最後一個元素,-2表示倒數第二個元素,以此類推。
127.0.0.1:6379> lrange listkey 0 -1 1) "b" 2) "a" 3) "a" 127.0.0.1:6379> lindex listkey 0 "b" 127.0.0.1:6379> lindex listkey -1 "a" 127.0.0.1:6379> lindex listkey 3 (nil) 127.0.0.1:6379>
blpop key [key …] timeout
blpop 是阻塞式的彈出命令,它是lpop key 命令的阻塞版本。當給定列表內沒有任何元素可供彈出的時候,鏈接將被 blpop 命令阻塞,直到等待超時或發現可彈出元素爲止。
當給定多個 key 參數時,按參數 key 的前後順序依次檢查各個列表,彈出第一個非空列表的頭元素。
所以能夠分兩種狀況討論,一種是至少有一個key存在且是非空列表,則blpop命令不會阻塞,另外是blpop命令中的列表是空列表,此時會在超時時間內阻塞。
先看下非阻塞的場景,返回值是第一個非空列表名和被彈出元素。
127.0.0.1:6379> lpush list1 hello java (integer) 2 127.0.0.1:6379> lpush list2 hello redis (integer) 2 127.0.0.1:6379> blpop list2 list1 list3 0 1) "list2" 2) "redis" 127.0.0.1:6379>
阻塞的場景,在執行了blpop book1 book2 300 命令後會一直阻塞住。
127.0.0.1:6379> exists book1 (integer) 0 127.0.0.1:6379> exists book2 (integer) 0 127.0.0.1:6379> blpop book1 book2 300 阻塞在這裏了
這個時候,咱們若是在開另一個redis客戶端,執行以下lpush
命令往book1列表中推入一個元素。
127.0.0.1:6379> lpush book1 springboot (integer) 1 127.0.0.1:6379>
此時,再回到原來阻塞的客戶端,已經彈出了元素。
127.0.0.1:6379> exists book1 (integer) 0 127.0.0.1:6379> exists book2 (integer) 0 127.0.0.1:6379> blpop book1 book2 300 1) "book1" 2) "springboot" (237.45s) 127.0.0.1:6379>
經過利用Redis列表類型的阻塞式命令的特性,咱們最容易想到的就是能夠用它實現一個簡易版的消息隊列。
Redis的集合以無序的方式存儲多個不一樣的元素。這裏要注意的是無序和不一樣。
除了對集合能快速執行添加、刪除、檢查一個元素是否在集合中以外,還能夠對多個集合執行交集、並集和差集運算。
Redis的集合類型底層實現主要是經過一種叫作字典的數據結構。不過Redis爲了追求極致的性能,會根據存儲的值是不是整數,選擇一種intset的數據結構。當知足必定條件後,會切換成字典的實現。
這裏大概解釋下字典
: 實際上是由一集鍵值對(key-value pairs)組成, 各個鍵值對的鍵各不相同, 程序能夠添加新的鍵值對到字典中, 或者基於鍵進行查找、更新或刪除等操做。
Redis的set(集合)在使用字典數據結構保存數據時,將元素保存到字典的鍵裏面, 而字典的值則統一設爲 NULL 。
sadd key member [member...]
將一個或者多個元素添加到集合key中,已存在於集合中的元素將被忽略。返回新添加的元素數量,不包括忽略的元素。
srem key member [member...]
移除集合中的一個或多個元素,不存在的元素將被忽略。返回被成功移除的元素數量。
sismember key meber
檢查元素member是否存在於集合key中。若是是返回1,不是或者key不存在,返回0。
scard key
返回集合包含的元素數量
spop key
隨機移除集合中的一個元素,並返回被移除元素。
smembers key
返回集合中包含的全部元素
127.0.0.1:6379> sadd set1 java spring redis (integer) 3 127.0.0.1:6379> smembers set1 1) "redis" 2) "spring" 3) "java" 127.0.0.1:6379> scard set1 (integer) 3 127.0.0.1:6379> srem set1 spring (integer) 1 127.0.0.1:6379> sismember set1 spring (integer) 0 127.0.0.1:6379> smembers set1 1) "redis" 2) "java" 127.0.0.1:6379> sadd set1 mysql spring (integer) 2 127.0.0.1:6379> spop set1 "redis" 127.0.0.1:6379> smembers set1 1) "mysql" 2) "spring" 3) "java" 127.0.0.1:6379>
下面是一些用於處理多個集合的一些命令
sdiff key [key...]
返回存在於第一個集合,但不存在於其餘集合中的元素(數學上的差集運算)
sinter key [key...]
返回同時存在於全部集合中的元素(數學上的交集運算)
sunion key [key...]
返回至少存在於一個集合中的元素(數學上的並集運算)
127.0.0.1:6379> smembers set1 1) "mysql" 2) "spring" 3) "java" 127.0.0.1:6379> smembers set2 1) "mysql" 2) "springboot" 3) "redis" 127.0.0.1:6379> sdiff set1 set2 1) "java" 2) "spring" 127.0.0.1:6379> sinter set1 set2 1) "mysql" 127.0.0.1:6379> sunion set1 set2 1) "mysql" 2) "springboot" 3) "java" 4) "spring" 5) "redis" 127.0.0.1:6379>
Redis的hash類型其實就是一個縮減版的redis。它存儲的是鍵值對,將多個鍵值對存儲到一個redis鍵裏面。
hash類型的底層主要也是基於字典這種數據結構來實現的。
redis內部在實現hash數據類型的時候是使用了兩種數據結構。在建立一個空的hash表時,默認使用的是ziplist的數據結構,知足必定條件後會轉成字典的形式。
hmget hash-key key [key...]
從散列表裏面獲取一個或多個鍵的值
hmset hash-key key value [key value...]
爲散列表裏面的一個或多個鍵設置值
hdel hash-key key [key...]
刪除散列表裏面的一個或多個鍵值對,返回刪除成功的鍵值對的數量
hlen hash-key
返回散列表包含的鍵值對的數量
hexists hash-key key
檢查給定的鍵是否存在於散列表中
hkeys hash-key
獲取散列包含的全部鍵
hvals hash-key
獲取散列包含的全部值
hgetall hash-key
獲取散列包含的全部鍵值對
127.0.0.1:6379> hmset hash1 username tom email 123@123 year 12 OK 127.0.0.1:6379> hmget hash1 email 1) "123@123" 127.0.0.1:6379> hlen hash1 (integer) 3 127.0.0.1:6379> hdel hash1 year (integer) 1 127.0.0.1:6379> hexists hash1 year (integer) 0 127.0.0.1:6379> hkeys hash1 1) "username" 2) "email" 127.0.0.1:6379> hvals hash1 1) "tom" 2) "123@123" 127.0.0.1:6379> hgetall hash1 1) "username" 2) "tom" 3) "email" 4) "123@123" 127.0.0.1:6379>
有序集合相比較於集合,多個有序兩個字,咱們知道set集合類型存儲的元素是無序的,那Redis有序集合是怎麼保證有序的?使用分值,有序集合裏存儲這成員與分值之間的映射,並提供了分值處理命令,以及根據分值的大小有序地獲取成員或分值的命令。
Redis有序集合的實現使用了一種叫跳躍表的數據結構(簡稱跳錶,可自行查閱),同時也使用到了前面提到的壓縮列表。也是知足必定條件的話,會自行轉換。
zadd z-key score memer [score member...]
將帶有給定分值的成員添加到有序集合裏面
zrem z-key member [member...]
從有序集合裏面移除給定的成員,並返回被移除成員的數量
zcard z-key
返回有序集合包含的成員數量
zincrby z-key increment member
將member成員的分值加上increment
zcount z-key min max
返回分值介於min和max之間的成員數量
zrank z-key member
返回成員member在有序集合中的排名
zscore z-key member
返回成員member的分值
zrange z-key start stop [withscores]
返回有序集合中排名介於start和stop之間的成員,若是給定了可選的withscores選項,name命令會將成員的分值也一併返回。
zrevrank z-key member
返回有序集合裏成員member的排名,成員按照分值從大到小排列。
zrevrange z-key start stop
返回有序集合給定排名範圍內的成員,成員按照分值從大到小排列。
zrangebyscore z-key min max
返回有序集合中分值介於min和max之間的全部成員
127.0.0.1:6379> zadd zset1 10 a 12 b 1 c 3 d 20 e (integer) 5 127.0.0.1:6379> zcard zset1 (integer) 5 127.0.0.1:6379> zcount zset1 2 10 (integer) 2 127.0.0.1:6379> zrank zset1 d (integer) 1 127.0.0.1:6379> zscore zset1 e "20" 127.0.0.1:6379> zrange zset1 3 5 1) "b" 2) "e" 127.0.0.1:6379> zrevrank zset1 d (integer) 3 127.0.0.1:6379> zrevrange zset1 3 5 1) "d" 2) "c" 127.0.0.1:6379> zrangebyscore zset1 5 10 1) "a" 127.0.0.1:6379>
做者Info: 公衆號:二營長的筆記 閒話:用技術築起本身的風牆,當外面的槍林彈雨來臨的時候,至少能夠來個「面對疾風吧!!!」