您好,登錄后才能下訂單哦!
這篇文章主要介紹“Redis常用數據結構有哪些及怎么實現”,在日常操作中,相信很多人在Redis常用數據結構有哪些及怎么實現問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Redis常用數據結構有哪些及怎么實現”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Redis提供了一些數據結構供我們往Redis中存取數據,最常用的的有5種,字符串(String)、哈希(Hash)、列表(list)、集合(set)、有序集合(ZSET)。
字符串類型是Redis最基礎的數據結構。首先鍵都是字符串類型,而且其他幾種數據結構都是在字符串類型基礎上構建的,所以字符串類型能為其他四種數據結構的學習奠定基礎。字符串類型的值實際可以是字符串(簡單的字符串、復雜的字符串(例如JSON、XML))、數字(整數、浮點數),甚至是二進制(圖片、音頻、視頻),但是值最大不能超過512MB。
(雖然Redis是C寫的,C里面有字符串<本質使用char數組來實現>,但是處于種種考慮,Redis還是自己實現了字符串類型)
set key value
set命令有幾個選項:
ex seconds: 為鍵設置秒級過期時間。
px milliseconds: 為鍵設置毫秒級過期時間。
nx: 鍵必須不存在,才可以設置成功,用于添加(分布式鎖常用)。
xx: 與nx相反,鍵必須存在,才可以設置成功,用于更新。
從執行效果上看,ex參數和expire命令基本一樣。還有一個需要特別注意的地方是如果一個字符串已經設置了過期時間,然后你調用了set 方法修改了它,它的過期時間會消失。
而nx和xx執行效果如下
除了set選項,Redis 還提供了setex和 setnx兩個命令:
setex key seconds value
setnx key value
setex和 setnx的作用和ex和nx選項是一樣的。也就是,setex為鍵設置秒級過期時間,setnx設置時鍵必須不存在,才可以設置成功。
setex示例:
setnx示例:
因為鍵foo-ex已存在,所以setnx失敗,返回結果為0,鍵foo-ex2不存在,所以setnx成功,返回結果為1。
有什么應用場景嗎?以setnx命令為例子,由于Redis的單線程命令處理機制,如果有多個客戶端同時執行setnx key value,根據setnx的特性只有一個客戶端能設置成功,setnx可以作為分布式鎖的一種實現方案。當然分布式鎖沒有不是只有一個命令就OK了,其中還有很多的東西要注意,我們后面會用單獨的章節來講述基于Redis的分布式鎖。
如果要獲取的鍵不存在,則返回nil(空):
通過mset命令一次性設置4個鍵值對
批量獲取了鍵a、b、c、d的值:
如果有些鍵不存在,那么它的值為nil(空),結果是按照傳入鍵的順序返回。
批量操作命令可以有效提高效率,假如沒有mget這樣的命令,要執行n次get命令具體耗時如下:
n次 get時間=n次網絡時間+n次命令時間
使用mget命令后,要執行n次get命令操作具體耗時如下:
n次get時間=1次網絡時間+n次命令時間
Redis可以支撐每秒數萬的讀寫操作,但是這指的是Redis服務端的處理能力,對于客戶端來說,一次命令除了命令時間還是有網絡時間,假設網絡時間為1毫秒,命令時間為0.1毫秒(按照每秒處理1萬條命令算),那么執行1000次 get命令需要1.1秒(10001+10000.1=1100ms),1次mget命令的需要0.101秒(11+10000.1=101ms)。
incr命令用于對值做自增操作,返回結果分為三種情況:
值不是整數,返回錯誤。
值是整數,返回自增后的結果。
鍵不存在,按照值為0自增,返回結果為1。
除了incr命令,Redis提供了decr(自減)、 incrby(自增指定數字)、decrby(自減指定數字)、incrbyfloat(自增浮點數),具體效果請同學們自行嘗試。
append可以向字符串尾部追加值
返回字符串長度
注意:每個中文占3個字節
getset和set一樣會設置值,但是不同的是,它同時會返回鍵原來的值
下標從0開始計算。
getrange 截取字符串中的一部分,形成一個子串,需要指明開始和結束的偏移量,截取的范圍是個閉區間。
字符串這些命令中,除了del 、mset、 mget支持多個鍵的批量操作,時間復雜度和鍵的個數相關,為O(n),getrange和字符串長度相關,也是O(n),其余的命令基本上都是O(1)的時間復雜度,在速度上還是非常快的。
字符串類型的使用場景很廣泛:
緩存功能
Redis 作為緩存層,MySQL作為存儲層,絕大部分請求的數據都是從Redis中獲取。由于Redis具有支撐高并發的特性,所以緩存通常能起到加速讀寫和降低后端壓力的作用。
計數
使用Redis 作為計數的基礎工具,它可以實現快速計數、查詢緩存的功能,同時數據可以異步落地到其他數據源。
共享Session
一個分布式Web服務將用戶的Session信息(例如用戶登錄信息)保存在各自服務器中,這樣會造成一個問題,出于負載均衡的考慮,分布式服務會將用戶的訪問均衡到不同服務器上,用戶刷新一次訪問可能會發現需要重新登錄,這個問題是用戶無法容忍的。
為了解決這個問題,可以使用Redis將用戶的Session進行集中管理,,在這種模式下只要保證Redis是高可用和擴展性的,每次用戶更新或者查詢登錄信息都直接從Redis中集中獲取。
限速
比如,很多應用出于安全的考慮,會在每次進行登錄時,讓用戶輸入手機驗證碼,從而確定是否是用戶本人。但是為了短信接口不被頻繁訪問,會限制用戶每分鐘獲取驗證碼的頻率,例如一分鐘不能超過5次。一些網站限制一個IP地址不能在一秒鐘之內方問超過n次也可以采用類似的思路。
Java里提供了HashMap,Redis中也有類似的數據結構,就是哈希類型。但是要注意,哈希類型中的映射關系叫作field-value,注意這里的value是指field對應的值,不是鍵對應的值。
基本上,哈希的操作命令和字符串的操作命令很類似,很多命令在字符串類型的命令前面加上了h字母,代表是操作哈希類型,同時還要指明要操作的field的值。
hset user:1 name lijin
如果設置成功會返回1,反之會返回0。此外Redis提供了hsetnx命令,它們的關系就像set和setnx命令一樣,只不過作用域由鍵變為field。
hget user:1 name
如果鍵或field不存在,會返回nil。
hdel會刪除一個或多個field,返回結果為成功刪除field的個數。
若存在返回1,不存在返回0
它返回指定哈希鍵所有的field
在使用hgetall時,如果哈希元素個數比較多,會存在阻塞Redis的可能。如果只需要獲取部分field,可以使用hmget,如果一定要獲取全部field-value,可以使用hscan命令,該命令會漸進式遍歷哈希類型,hscan將在后面的章節介紹。
hincrby和 hincrbyfloat,就像incrby和incrbyfloat命令一樣,但是它們的作用域是filed。
哈希類型的操作命令中,hdel,hmget,hmset的時間復雜度和命令所帶的field的個數相關O(k),hkeys,hgetall,hvals和存儲的field的總數相關,O(N)。其余的命令時間復雜度都是O(1)。
從前面的操作可以看出,String和Hash的操作非常類似,那為什么要弄一個hash出來存儲。
哈希類型比較適宜存放對象類型的數據,我們可以比較下,如果數據庫中表記錄user為:
id | name | age |
---|---|---|
1 | lijin | 18 |
2 | msb | 20 |
1、使用String類型
需要一條條去插入獲取。
set user:1:name lijin;
set user:1:age 18;
set user:2:name msb;
set user:2:age 20;
優點:簡單直觀,每個鍵對應一個值
缺點:鍵數過多,占用內存多,用戶信息過于分散,不用于生產環境
2、將對象序列化存入redis
set user:1 serialize(userInfo);
優點:編程簡單,若使用序列化合理內存使用率高
缺點:序列化與反序列化有一定開銷,更新屬性時需要把userInfo全取出來進行反序列化,更新后再序列化到redis
3、使用hash類型
hmset user:1 name lijin age 18
hmset user:2 name msb age 20
優點:簡單直觀,使用合理可減少內存空間消耗
缺點:要控制內部編碼格式,不恰當的格式會消耗更多內存
列表( list)類型是用來存儲多個有序的字符串,a、b、c、c、b四個元素從左到右組成了一個有序的列表,列表中的每個字符串稱為元素(element),一個列表最多可以存儲(2^32-1)個元素(4294967295)。
在Redis 中,可以對列表兩端插入( push)和彈出(pop),還可以獲取指定范圍的元素列表、獲取指定索引下標的元素等。列表是一種比較靈活的數據結構,它可以充當棧和隊列的角色,在實際開發上有很多應用場景。
列表類型有兩個特點:
第一、列表中的元素是有序的,這就意味著可以通過索引下標獲取某個元素或者某個范圍內的元素列表。
第二、列表中的元素可以是重復的。
key start end
索引下標特點:從左到右為0到N-1
lrange 0 -1命令可以從左到右獲取列表的所有元素
這三個返回結果為命令完成后當前列表的長度,也就是列表中包含的元素個數,同時rpush和lpush都支持同時插入多個元素。
r
請注意,彈出來元素就沒了。
rpop將會把列表最右側的元素d彈出。
lrem命令會從列表中找到等于value的元素進行刪除,根據count的不同分為三種情況:
count>0,從左到右,刪除最多count個元素。
count<0,從右到左,刪除最多count絕對值個元素。
count=0,刪除所有。
返回值是實際刪除元素的個數。
例如想保留列表中第0個到第1個元素
ls
l
blpop和brpop是lpop和rpop的阻塞版本,除此之外還支持多個列表類型,也支持設定阻塞時間,單位秒,如果阻塞時間為0,表示一直阻塞下去。我們以brpop為例說明。
A客戶端阻塞了(因為沒有元素就會阻塞)
A客戶端一直處于阻塞狀態。此時我們從另一個客戶端B執行
A客戶端則輸出
注意:brpop后面如果是多個鍵,那么brpop會從左至右遍歷鍵,一旦有一個鍵能彈出元素,客戶端立即返回。
列表類型可以用于比如:
消息隊列,Redis 的 lpush+brpop命令組合即可實現阻塞隊列,生產者客戶端使用lrpush從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞式的“搶”列表尾部的元素,多個客戶端保證了消費的負載均衡和高可用性。
文章列表
每個用戶有屬于自己的文章列表,現需要分頁展示文章列表。此時可以考慮使用列表,因為列表不但是有序的,同時支持按照索引范圍獲取元素。
實現其他數據結構
lpush+lpop =Stack(棧)
lpush +rpop =Queue(隊列)
lpsh+ ltrim =Capped Collection(有限集合)
lpush+brpop=Message Queue(消息隊列)
集合( set)類型也是用來保存多個的字符串元素,但和列表類型不一樣的是,集合中不允許有重復元素,并且集合中的元素是無序的,不能通過索引下標獲取元素。
一個集合最多可以存儲2的32次方-1個元素。Redis除了支持集合內的增刪改查,同時還支持多個集合取交集、并集、差集,合理地使用好集合類型,能在實際開發中解決很多實際問題。
允許添加多個,返回結果為添加成功的元素個數
允許刪除多個,返回結果為成功刪除元素個數
如果給定元素element在集合內返回1,反之返回0
指定個數如果不寫默認為1
同樣可以指定個數,如果不寫默認為1,注意,既然是彈出,spop命令執行后,元素會從集合中刪除,而srandmember不會。
返回結果是無序的
現在有兩個集合,它們分別是set1和set2
sinterstore destination key [key ...] suionstore destination key [key ...] sdiffstore destination key [key ...]復制代碼
集合間的運算在元素較多的情況下會比較耗時,所以 Redis提供了上面三個命令(原命令+store)將集合間交集、并集、差集的結果保存在destination key中,例如:
集合類型比較典型的使用場景是標簽(tag)。例如一個用戶可能對娛樂、體育比較感興趣,另一個用戶可能對歷史、新聞比較感興趣,這些興趣點就是標簽。有了這些數據就可以得到喜歡同一個標簽的人,以及用戶的共同喜好的標簽,這些數據對于用戶體驗以及增強用戶黏度比較重要。
例如一個電子商務的網站會對不同標簽的用戶做不同類型的推薦,比如對數碼產品比較感興趣的人,在各個頁面或者通過郵件的形式給他們推薦最新的數碼產品,通常會為網站帶來更多的利益。
除此之外,集合還可以通過生成隨機數進行比如抽獎活動,以及社交圖譜等等。
有序集合相對于哈希、列表、集合來說會有一點點陌生,但既然叫有序集合,那么它和集合必然有著聯系,它保留了集合不能有重復成員的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下標作為排序依據不同的是,它給每個元素設置一個分數( score)作為排序的依據。
有序集合中的元素不能重復,但是score可以重復,就和一個班里的同學學號不能重復,但是考試成績可以相同。
有序集合提供了獲取指定分數和元素范圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題。
返回結果代表成功添加成員的個數
要注意:
zadd命令還有四個選項nx、xx、ch、incr 四個選項
nx: member必須不存在,才可以設置成功,用于添加。
xx: member必須存在,才可以設置成功,用于更新。
ch: 返回此次操作后,有序集合元素和分數發生變化的個數
incr: 對score做增加,相當于后面介紹的zincrby
如果成員不存在則返回nil
zrank是從分數從低到高返回排名
zrevrank反之
很明顯,排名從0開始計算。
允許一次刪除多個成員。
返回結果為成功刪除的個數。
有序集合是按照分值排名的,zrange是從低到高返回,zrevrange反之。如果加上 withscores選項,同時會返回成員的分數
zrangebyscore key min max [withscores] [limit offset count] zrevrangebyscore key max min [withscores][limit offset count]復制代碼
其中zrangebyscore按照分數從低到高返回,zrevrangebyscore反之。例如下面操作從低到高返回200到221分的成員,withscores選項會同時返回每個成員的分數。
同時min和max還支持開區間(小括號)和閉區間(中括號),-inf和+inf分別代表無限小和無限大:
zcount key min max
zremrangebyrank key start end
zremrangebyscore key min max
zinterstore
這個命令參數較多,下面分別進行說明
destination:交集計算結果保存到這個鍵。
numkeys:需要做交集計算鍵的個數。
key [key ...]:需要做交集計算的鍵。
weights weight [weight ...]:每個鍵的權重,在做交集計算時,每個鍵中的每個member 會將自己分數乘以這個權重,每個鍵的權重默認是1。
aggregate sum/ min |max:計算成員交集后,分值可以按照sum(和)、min(最小值)、max(最大值)做匯總,默認值是sum。
不太好理解,我們用一個例子來說明。(算平均分)
該命令的所有參數和zinterstore是一致的,只不過是做并集計算,大家可以自行實驗。
到此,關于“Redis常用數據結構有哪些及怎么實現”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。