1. redis中list和hash的基本命令和使用場景
Redis的數據類型
Redis的數據類型共有五種:string,list,hash,set,zset;
String 字元串相對來說做平常,key-value,類似是hashmap的用法;
List 隊列,可以雙向的存值,設計時,也可以簡單用來當隊列模式;
Hash 字典,一個key 對應多個值;
Set 無序的集合;
Zset 有序的集合;
列表 list
Redis列表是簡單的字元串列表,按照插入順序排序。你可以添加一個元素導列表的頭部(左邊)或者尾部(右邊)
列表 list—— 基本命令
lpush
語法:lpush key value [value„]
作用:將一個或多個值 value 插入到列表 key 的表頭(最左邊),從左邊開始加入值,從左到右的順序依次插入到表頭
返回值:數字,新列表的長度
rpush
語法:rpush key value [value„]
作用:將一個或多個值 value 插入到列表 key 的表尾(最右邊),各個 value 值按從左到右 的順序依次插入到表尾
返回值:數字,新列表的長度
lrange
語法:lrange key start stop
作用:獲取列表 key 中指定區間內的元素,0 表示列表的第一個元素,以 1 表示列表的第二個元素;
start ,
stop 是列表的下標值,也可以負數的下標, -1 表示列表的最後一個元素, -2 表示列表的倒 數第二個元素,以此類推。
start ,stop 超出列表的范圍不會出現錯誤。
返回值:指定區間的列表
lindex
語法:lindex key index
作用:獲取列表 key 中下標為指定 index 的元素,列表元素不刪除,只是查詢。
0 表示列表的第一個元素,以 1 表示列表的第二個元素;
start ,
stop 是列表的下標值,也可以負數的下標, -1 表示列表的最後一個元素, -2 表示列表的倒數第二個元素,以此類推。
返回值:指定下標的元素;index 不在列表范圍,返回nil
llen
語法:llen key
作用:獲取列表 key 的長度 返回值:數值,列表的長度; key 不存在返回0
lrem
語法:lrem key count value
作用:根據參數count的值,移除列表中與參數value相等的元素,
count>0,從列表的左側向右開始移 除;
count<0從列表的尾部開始移除;
count=0 移除表中所有與value相等的值。
返回值:數值,移除的元素個數
lset
語法:lset key index value
作用:將列表 key 下標為 index 的元素的值設置為 value。
返回值:設置成功返回 ok ; key 不存在或者 index 超出范圍返回錯誤信息
linsert
語法:linsert key BEFORE(前)|AFTER(後) pivot value
作用:
將值value插入到列表key當中位於值pivot之前或之後的位置。
key不存在,pivot不在列表中, 不執行任何操作。
返回值:命令執行成功,返回新列表的長度。沒有找到 pivot 返回 -1, key 不存在返回 0。
RPOP key
移除列表的最後一個元素,返回值為移除的元素。
RPOPLPUSH source destination
移除列表的最後一個元素,並將該元素添加到另一個列表並返回
LPOP key
移除列表的第一個元素,返回值為移除的元素。
使用場景
1. 消息隊列
隊列模式的情況下,可以使用,左進右出的原則,但不建議使用,因為現在市面上有很多成熟的消息中間件,沒有必要造輪子;
2.排行榜
某一段時間統計數據的排行榜可以放在list裡面,需要分頁的話,也可以使用lrange start stop實現;
3. list類型的lpush命令和lrange命令能實現最新列表的功能,每次通過lpush命令往列表裡插入新的元素,然後通過lrange命令讀取最新的元素列表,如朋友圈的點贊列表、評論列表。
但是,並不是所有的最新列表都能用list類型實現,因為對於頻繁更新的列表,list類型的分頁可能導致列表元素重復或漏掉,舉個例子,當前列表裡由表頭到表尾依次有(E,D,C,B,A)五個元素,每頁獲取3個元素,用戶第一次獲取到(E,D,C)三個元素,然後表頭新增了一個元素F,列表變成了(F,E,D,C,B,A),此時用戶取第二頁拿到(C,B,A),元素C重復了。只有不需要分頁(比如每次都只取列表的前5個元素)或者更新頻率低(比如每天凌晨更新一次)的列表才適合用list類型實現
哈希類型hash
redis hash是一個 string 類型的 field 和 value 的映射表,hash特別適合用於存儲對象,每個 hash 可以存儲 232 - 1鍵值對(40多億);
哈希類型 hash—— 基本命令
hset /hget /hmset /hmget /hgetall /hkeys /hvals /hexists
hset
語法:hset hash 表的key field value
作用:將哈希表 key 中的域 field 的值設為value ,如果 key 不存在,則新建 hash 表,執行賦值,如果有 field ,則覆蓋值。
返回值: ①如果 field 是 hash 表中新field,且設置值成功,返回 1 ②如果 field 已經存在,舊值覆蓋新值,返回0
hget
語法:hget key field
作用:獲取哈希表 key 中給定域 field 的值
返回值:field 域的值,如果 key 不存在或者 field 不存在返回nil
hmset
語法:hmset key field value [field value„]
說明:同時將多個field-value(域-值)設置到哈希表key中,此命令會覆蓋已經存在的field, hash表key不存在,創建空的hash表,執行hmset.
返回值:設置成功返回ok, 如果失敗返回一個錯誤
hmget
語法:hmget key field [field„]
作用:獲取哈希表key中一個或多個給定域的值
返回值:返回和field順序對應的值,如果field不存在,返回nil
hgetall
語法:hgetall key
作用:獲取哈希表key中所有的域和值
返回值:以列表形式返回hash中域和域的值 ,key不存在,返回空hash
hdel
語法:hdel key field [field„]
作用:刪除哈希表 key 中的一個或多個指定域 field,不存在 field 直接忽略
返回值:成功刪除的 field 的數量
hkeys
語法:hkeys key
作用:查看哈希表 key 中的所有 field 域
返回值:包含所有 field 的列表,key 不存在返回空列表
hvals
語法:hvals key
作用:返回哈希表中所有域的值 返回值:包含哈希表所有域值的列表,key 不存在返回空列表
hexists
語法:hexists key field
作用:查看哈希表 key 中,給定域 field 是否存在
返回值:如果 field 存在,返回 1, 其他返回0
使用場景
1、購物車
以用戶id為key,商品id為field,商品數量為value,恰好構成了購物車的3個要素,如下圖所示。
2、hash還是比較適合存儲對象(key field value)或者是字典表(type,key,vlaue),剛好符合對象的要素,但string + json也可以存儲,兩則比較有什麼區別?
String + json Hash
效率很 高 高
容量 低 低
靈活性 低 高
序列化 簡單 復雜
2. Redis --- 八種數據類型(基本命令)
String、Hash、List、Set和Zset。
等同於java中的, Map<String,String> string 是redis裡面的最基本的數據類型,一個key對應一個value。
應用場景 :String是最常用的一種數據類型,普通的key/value存儲都可以歸為此類,如用戶信息,登錄信息和配置信息等;
實現方式 :String在redis內部存儲默認就是一個字元串,被redisObject所引用,當遇到incr、decr等操作(自增自減等原子操作)時會轉成數值型進行計算,此時redisObject的encoding欄位為int。
Redis雖然是用C語言寫的,但卻沒有直接用C語言的字元串,而是自己實現了一套字元串。目的就是為了提升速度,提升性能。 Redis構建了一個叫做簡單動態字元串(Simple Dynamic String),簡稱SDS。
Redis的字元串也會遵守C語言的字元串的實現規則,即 最後一個字元為空字元。然而這個空字元不會被計算在len里頭。
Redis動態擴展步驟:
Redis字元串的性能優勢
常用命令 :set/get/decr/incr/mget等,具體如下;
ps:計數器(字元串的內容為整數的時候可以使用),如 set number 1。
補充:
等同於java中的: Map<String,Map<String,String>> ,redis的hash是一個string類型的field和value的映射表, 特別適合存儲對象。 在redis中,hash因為是一個集合,所以有兩層。第一層是key:hash集合value,第二層是hashkey:string value。所以判斷是否採用hash的時候可以參照有兩層key的設計來做參考。並且注意的是, 設置過期時間只能在第一層的key上面設置。
應用場景 :我們要存儲一個用戶信息對象數據,其中包括用戶ID、用戶姓名、年齡和生日,通過用戶ID我們希望獲取該用戶的姓名或者年齡或者生日;
實現方式 :Redis的Hash實際是內部存儲的Value為一個HashMap,並提供了直接存取這個Map成員的介面。如,Key是用戶ID, value是一個Map。 這個Map的key是成員的屬性名,value是屬性值 。這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據。 當前HashMap的實現有兩種方式 :當HashMap的成員比較少時Redis為了節省內存會採用類似一維數組的方式來緊湊存儲,而不會採用真正的HashMap結構,這時對應的value的redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時redisObject的encoding欄位為int。
常用命令 :hget/hset/hgetall等,具體如下:
等同於java中的 Map<String,List<String>> ,list 底層是一個鏈表,在redis中,插入list中的值,只需要找到list的key即可,而不需要像hash一樣插入兩層的key。 list是一種有序的、可重復的集合。
應用場景 :Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現;
實現方式 :Redis list的實現為一個 雙向鏈表 ,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括 發送緩沖隊列 等也都是用的這個數據結構。
常用命令 :lpush/rpush/lpop/rpop/lrange等,具體如下:
性能總結 :
它是一個字元串鏈表,left、right都可以插入添加。
等同於java中的 Map<String,Set<String>> ,Set 是一種無序的,不能重復的集合。並且在redis中,只有一個key它的底層由hashTable實現的,天生去重。
應用場景 :Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動去重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,並且 set提供了判斷某個成員是否在一個set集合內的重要介面 ,這個也是list所不能提供的;如保存一些標簽的名字。標簽的名字不可以重復,順序是可以無序的。
實現方式 :set 的內部實現是一個 value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。
常用命令 :sadd/spop/smembers/sunion等,具體如下:
ZSet(Sorted Set:有序集合) 每個元素都會關聯一個double類型的分數score,分數允許重復,集合元素按照score排序( 當score相同的時候,會按照被插入的鍵的字典順序進行排序 ),還可以通過 score 的范圍來獲取元素的列表。
應用場景 :Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以 通過用戶額外提供一個優先順序(score)的參數來為成員排序,並且是插入有序的,即自動排序。 當你需要一個有序的並且不重復的集合列表,那麼可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。
底層實現 : zset 是 Redis 提供的一個非常特別的數據結構,常用作排行榜等功能,以用戶 id 為 value ,關注時間或者分數作為 score 進行排序。實現機制分別是 zipList 和 skipList 。規則如下:
zipList:滿足以下兩個條件
skipList:不滿足以上兩個條件時使用跳錶、組合了hash和skipList
為什麼用skiplist不用平衡樹?
主要從內存佔用、對范圍查找的支持和實現難易程度這三方面總結的原因。
拓展:mysql為什麼不用跳錶?
常用命令 :zadd/zrange/zrem/zcard等;
官網地址: https://redis.io/commands/geoadd
可以用來推算兩地之間的距離,方圓半徑內的人。
關於經度緯度的限制: https://www.redis.net.cn/order/3685.html
一般我們使用Hyperloglog做基數統計。
什麼是基數?就是一個集合中不重復的數的個數。
集合A:{1,3,5,7,9,7}
集合B:{1,3,5,7,9}
AB集合的基數都是5
應用:統計網站的訪問量(一個人訪問網站很多次仍然算作一次)。
優點:佔用的內存是固定的,找2^64次方個數的基數,只需要12KB內存。
缺點:有0.81%的錯誤率,可以忽略不計
概述: bitmap 存儲的是連續的二進制數字(0 和 1),通過 bitmap, 只需要一個 bit 位來表示某個元素對應的值或者狀態,key 就是對應元素本身 。 我們知道 8 個 bit 可以組成一個 byte,所以 bitmap 本身會極大的節省儲存空間。
應用場景: 適合需要保存狀態信息(比如是否簽到、是否登錄...)並需要進一步對這些信息進行分析的場景。比如用戶簽到情況、活躍用戶情況、用戶行為統計(比如是否點贊過某個視頻)。
針對上面提到的一些場景,這里進行進一步說明。
使用場景一:用戶行為分析 很多網站為了分析你的喜好,需要研究你點贊過的內容。
使用場景二:統計活躍用戶
使用時間作為 key,然後用戶 ID 為 offset,如果當日活躍過就設置為 1
那麼我該如果計算某幾天/月/年的活躍用戶呢(暫且約定,統計時間內只有有一天在線就稱為活躍),有請下一個 redis 的命令
使用場景三:用戶在線狀態
對於獲取或者統計用戶在線狀態,使用 bitmap 是一個節約空間效率又高的一種方法。
只需要一個 key,然後用戶 ID 為 offset,如果在線就設置為 1,不在線就設置為 0。
補充 :
巨人的肩膀:
https://www.cnblogs.com/Small-sunshine/p/11687809.html
https://mp.weixin.qq.com/s/CMu7oXVIKp2s-PXTdMlimA
3. 深入了解Redis操作五大數據類型常用命令
我們知道Redis默認有16個資料庫,默認是第0個資料庫,那麼如果在需要對資料庫進行切換的時候,我們就可以使用下面這個命令:
使用如下命令進行切換
如果想要清除指定某一個資料庫的數據
清除所有資料庫的數據
接下來這個命令應該是最常用的了
平常在開發中,我們還需要經常對key進行判斷,判斷其是否存在
因為我們設置的緩存數據一般都不能是永久的,這個時候就需要我們在存儲數據的時候,就為其設置過期時間。
string類型是Redis中五大基本數據類型之一,這也是最常使用到的一個數據類型,所有很多小夥伴們對Redis的認識和操作就僅僅的停留在了對Redis的操作層面,但是你是否知道string類型中的相關命令,還是有非常多實用的
接下來先看一下對string類型進行基本存儲和獲取的命令。
如果我們存儲的string中的內容是數字的話,我們也可以對其進行增或減操作,Redis可以自動的對字元串進行相關的操作。實現的命令如下:
使用msetnx時,同時設置一個或多個 key-value 對,當且僅當所有給定 key都不存在時才成立。
getset命令從字面意思就可以看出來,他的作用是先get再set。
總結string類似的使用場景:
在使用list類型進行存取的時候,有兩個命令需要進行區分:
注意:只有pop和push才分左右,其他的l都是list的意思
總結:
總結set集合一般用於元素的不重復的場景,比如抽獎系統,輪播等場景下
在使用hash集合的時候,要注意,hash其實就是一個Map集合,key-map的時候,值是一個map集合的形式進行存儲的,也和Java中的hashmap有一個類似。
HVALS獲取所有的value,HKEYS獲取所有的key,HGETALL獲取所有的鍵值
總結:
hash可以用於存儲變更的數據,比如user,name,age等,尤其是用戶信息之類的,hash更加適合用於對象的存儲,string更加適合用於字元串的存儲。
在set集合的基礎上增加一個序列號,來進行排序
ZRANGEBYSCORE使用語法
總結
以上是在對五種數據類型進行存取時的一些常用命令操作。關於其他的命令使用,小夥伴們在用到的時候可以直接入官網查看就可以了。
4. 後端開發應該掌握的Redis基礎
在這篇文章中,我們來講一講Redis的數據結構和通用命令。
Redis支持多種不同的數據結構,包括5種基礎數據結構和幾種比較復雜的數據,這些數據結構可以滿足不同的應用場景。
五種基礎數據結構
復雜的數據結構
不同數據結構的相同之處
從上面的介紹,我們看到支持的數據結構的不同,但其實,Redis的每一種數據結構都由一個key和value組成,可以抽象為:
Redis數據結構組成
而所有數據結構的key的值都是任意合法的字元串,不同的數據結構的區別就在於value存儲的值的不同而不同。
比如,最簡簡單的String數據結構,其value為String,所以String可以表示為:
而Hash數據結構,其value為一個哈希列表,所以Hash可以表示為:
這里就列出String和Hash來講解說明,關於更多數據結構的內部結構及詳細操作,我們在之後的文章在再談談吧。
Redis官網將Redis的命令按照功能劃分為15個主題分組,其中,Kyes主題的命令對所有的數據結構都通用,因此,有必要在了解其他數據結構命令前好好學習一下。
keys
keys命令的作用是列出Redis所有的key,該命令的時間復雜度為 O(N) , N 隨著Redis中key的數量增加而增加,因此Redis有大量的key,keys命令會執行很長時間,而由於Redis是單線程,某個命令耗費過長時間,則會導致後面的的所有請求無法得到響應,因此,千萬不要在生產伺服器上使用keys命令。
示例
exists
exists命令用於判斷一個或多個key是否存在,判斷多個key時,key之間用空格分隔,exists的返回值為整數,表示當前判斷有多少個key是存在的。
示例
del
del命令用於刪除一個或多個key,多個key之間用空格分隔,其返回值為整數,表示成功刪除了多少個存在的key,因此,如果只刪除一個key,則可以從返回值中判斷是否成功,如果刪除多個key,則只能得到刪除成功的數量。
示例
expire,pexpire
expire設置key在多少秒之後過期,pexpire設置key在多少毫秒之後過期,成功返回1,失敗返回0。
示例
ttl,pttl
ttl和pttl命令用於獲取key的過期時間,其返回值為整型,代表的意義分為幾種情況:
示例(ttl的演示,pttl類似)
expireat,pexpireat
設置key在某個時間戳過期,expreat參數時間戳用秒錶示,而pexpireat則用毫秒錶示,與expire和pexpire功能類似,返回1表示成功,0表示失敗。
示例
persist
移除key的過期時間,將key設置為永久有效,當key設置了過期時間,使用persist命令移除後返回1,如果key不存在或本身就是永久有效的,則返回0。
示例
type
判斷key是什麼類型的數據結構,返回值為string,list,set,hash,zset,分別表示我們前面介紹的Redis的5種基礎數據結構。
示例
上面介紹的是Redis中最常用的通用命令,雖然簡單,但還是非常有必要掌握其用法和使用方面要注意的事項,其實,對於普通開發人員來說,很多時候,也只是使用這些基礎通用的命令來操作Redis而已。