Redis實戰 | 5種Redis數據類型詳解

咱們知道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這塊已經涼涼了。程序員

string | 字符串類型

redis的字符串類型,能夠存儲字符串、整數或者浮點數。若是存儲的是整數或者浮點數,還能執行自增或者自減操做。面試

而且redis的string類型是二進制安全的,它能夠包含任何數據,好比一個序列化的對象、一個圖片字節流等。不過存儲大小是由上限的-512Mredis

這裏解釋下二進制安全的含義:簡單的來講,就是字符串不是根據某種特殊的標誌位來(C語言的\0)解析的,不管輸入的是什麼,總能保證輸出是處理的原始輸入而不是根據某種特殊格式來處理。spring

redis是怎麼實現string類型的二進制安全的呢?

答案是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 命令將覆蓋已有的值。

說明一下:

  • SETNX 是『SET if Not eXists』(若是不存在,則 SET)的簡寫。命令在設置成功時返回 1 , 設置失敗時返回 0 。
  • SETEX命令至關於SET key value 和 EXPIRE key seconds # 設置生存時間兩條命令的效果,可是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

List | 列表類型

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>
  • list類型能夠加入重複的元素,這個和後面要說的set(集合類型)不一樣。
  • lrange listkey 0 -1 是獲取整個列表的內容
  • 相似地rpush命令是從列表右端加入元素

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列表類型的阻塞式命令的特性,咱們最容易想到的就是能夠用它實現一個簡易版的消息隊列。

set | 集合類型

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>

hash | 散列表(哈希表)

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>

zset | 有序集合

有序集合相比較於集合,多個有序兩個字,咱們知道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: 公衆號:二營長的筆記 閒話:用技術築起本身的風牆,當外面的槍林彈雨來臨的時候,至少能夠來個「面對疾風吧!!!」

相關文章
相關標籤/搜索