Redis的各類數據類型到底能玩出什麼花兒?




兩個星期終於肝了出來,Redis相關問題腦圖,終於整理完了!!!
文末無套路分享~~附獲取方式







Redis做爲一款NoSQL內存數據庫,其豐富的數據類型、簡單易用的命令、單機可達10萬的高併發(官方數據),從面世以來就深受廣大用戶的喜好。Redis的五種數據類型,是咱們學習Redis時的必修課,可是大多數人都只是去學它的命令、API,殊不知道這些數據類型都能應用在哪些場景,那這些命令學起來也就會很快就忘,終究只是「紙上談兵」。


用好這五種數據類型將給你的開發帶來很大的便利,給你的程序帶來很大的性能提高,同時這五種數據類型能玩出不少花樣。javascript


不過大多數同窗,在實際的開發過程當中,大多隻用到了Redis五種數據類型中的1-3種,甚至有的只用過一種String類型。要麼是業務場景簡單用string足矣,要麼就是根本不知道或想不到用別的數據類型更合適,那麼即便是有些場景更適合用別的數據類型,可能本身也發覺不到。因此今天就來聊聊Redis的各類數據類型以及各自適用於什麼場景。


其實這個問題也是面試中問到Redis時的一個「開篇詞」,問這個問題主要有兩個緣由:css


第一,看看你到底有沒有全面的瞭解Redis有哪些功能,通常怎麼來用,什麼場景用什麼數據類型,就怕你只會最簡單的kv操做java

第二,看看你在實際項目裏都怎麼玩兒過Redis,經驗是否豐富android

 

要是你回答的很差,沒說出幾種數據類型,也沒說什麼場景,你完了,面試官對你印象確定很差,以爲你平時就是作個簡單的set和get,沒思考過。nginx

 

廢話很少說,進入正題吧。Redis一共提供了5種數據類型,分別是String,Hash,List,Set,sorted set(Zset),下面就從各個數據類型的基本經常使用命令和使用場景分別說說吧。web





String字符串




String字符串結構的經常使用命令面試

#字符串經常使用操做SET key value //存入字符串鍵值對MSET key value [key value ...] //批量存儲字符串鍵值對SETNX key value //存入一個不存在的字符串鍵值對GET key //獲取一個字符串鍵值MGET key [key ...] //批量獲取字符串鍵值DEL key [key ...] //刪除一個鍵EXPIRE key seconds //設置一個鍵的過時時間(秒)#原子加減INCR key //將key中儲存的數字值加1DECR key //將key中儲存的數字值減1INCRBY key increment //將key所儲存的值加上incrementDECRBY key decrement //將key所儲存的值減去decrement

這裏列出了一些String經常使用命令,咱們看一下這些String類型的這些命令能夠應用到哪些場景。redis


應用場景spring

一、單值緩存sql

即最簡單的key-value的set和get,好比緩存個標識,開關等


SET key valueGET key


二、對象緩存

除了單值緩存咱們還能夠用String類型緩存對象,以下兩種方式:

#1SET user:1 value(json串)GET user:1#2MSET user:1:name 編程大道 user:1:sex 1MGET user:1:name user:1:sex


第一種直接將對象轉換成json串做爲value存儲到redis,這種獲取對象就比較簡單了,直接get key拿到value轉成對象便可,但有個缺點就是若是你要是修改對象的某一個字段,也得把整個對象的json串拿出來反序列化成對象,這將帶來沒必要要的網絡開銷(即使是redis存在內存中,但實際咱們的應用服務器和redis是隔離的,網絡傳輸的開銷也不容小覷),一樣,頻繁的序列化反序列化也將會帶來不小的性能開銷,若是對於性能要求比較高的系統來講這將是一個災難。


而第二種存儲對象的方式則對於這種頻繁修改對象某一個字段的場景就比較友好了,每一個字段與值都是一個kv對,修改直接set k v覆蓋就行了,可是存儲多個字段時就沒那麼容易了,好在有mset批量操做的命令,網絡開銷由屢次變爲1次。


三、分佈式鎖

以下setnx命令是set if not exit的縮寫,意思就是這個key不存在時才執行set。多個線程執行這條命令時只有一個線程會執行成功,則視爲拿到鎖。而後拿到鎖的線程執行業務操做,執行完畢刪除這個鎖,釋放鎖。


#setnx key valueSETNX product:10001 true //返回1表明獲取鎖成功SETNX product:10001 true //返回0表明獲取鎖失敗//執行業務操做DEL product:10001 //執行完業務釋放鎖

上述方式存在問題:程序意外終止可能會致使鎖沒辦法釋放,形成死鎖。可使用以下命令,既設置分佈式鎖又設置了key的過時時間

SET product:10001 true ex 10 nx //防止程序意外終止致使死鎖

分Redis布式鎖的詳細實現能夠參考我以前寫的Redis分佈式鎖實戰


四、計數器


INCR article:readcount:{文章id}GET article:readcount:{文章id}

基於Redis原子自增命令incr能夠實現諸如計數器的功能,咱們都知道公衆號文章,微博,博客都有一個閱讀量的概念,咱們就能夠用這個計數器來實現,並且性能很高。


例以下圖中的閱讀數就能夠用redis的自增來實現


五、Web集羣session共享解決方案

系統集羣部署狀況下首先要考慮的問題就是session共享問題,咱們能夠經過將本來存儲在內存中由tomcat管理的session轉移到由Redis來存儲,實現分佈式session的功能。spring框架提供了session共享的解決方案,即spring session + redis實現分佈式session。


六、分佈式系統全局序列號

分佈式系統中要保證全局序列號的惟一性,可使用Redis來維護一個自增的序列。

經過以下命令從Redis獲取自增ID:

INCR orderId//INCR是一個原子自增命令

分佈式系統環境下經過Redis保證ID的自增性和惟一性,經過該命令獲取ID每次都要和Redis進行交互,若是業務量很大,那麼這將會很頻繁。


因此能夠一次性獲取必定量的ID保存在JVM內存中,用完了再從Redis獲取。這樣減小了頻繁的網絡開銷,可是缺點是可能會丟失(浪費)一部分ID,由於獲取後服務可能掛了還沒用完的ID可能就浪費了(固然你可使用一些手段去保證不浪費,但不必,浪費一點也是無所謂的)。

以下,每次獲取1000個

INCRBY orderId 1000//redis批量生成序列號提高性能




HASH結構

Hash經常使用操做


HSET key field value//存儲一個哈希表key的鍵值HSETNX key field value//存儲一個不存在的哈希表key的鍵值HMSET key field value [field value ...] //在一個哈希表key中存儲多個鍵值對HGET key field//獲取哈希表key對應的field鍵值HMGET key field [field ...]//批量獲取哈希表key中多個field鍵值HDEL key field [field ...]//刪除哈希表key中的field鍵值HLEN key//返回哈希表key中field的數量HGETALL key//返回哈希表key中全部的鍵值HINCRBY key field increment//爲哈希表key中field鍵的值加上增量increment


應用場景

一、對象緩存

結合HASH結構的key-field-value的特性,相似於Java中的HashMap,內部也是「key-value」的形式,field恰好能夠存對象的屬性名,假設有以下數據,

咱們能夠用HMSET命令批量設置field-value,前面拼接用戶的ID保證存多個用戶的數據不會重複;HMGET批量獲取field;MSET修改某一個field。


HMSET achievement {userId}:name 小明 {userId}:score 89HMSET achievement 1:name 小明 1:score 89HMSET achievement 2:name 小華 2:score 92HMGET achievement 1:name 1:score

對象與HSAH的關係就變成了下圖這樣


二、電商購物車

以用戶id爲key,商品id爲field,商品數量爲value能夠實現購物車的常規操做。


購物車操做:


#添加商品hset cart:10001 50005 1#給某一個商品增長數量hincrby cart:10001 50005 1#購物車中商品總個數hlen cart:10001#刪除商品hdel cart:10001 50005#獲取購物車全部商品hgetall cart:10001


對應購物車的幾個經常使用操做能夠想象使用Redis如何實現



Hash結構優缺點

優勢

  • 將同類數據歸類整合儲存(同一個key),方便數據管理

  • 相比String操做,對內存與cpu的消耗更小

  • 相比String儲存更節省空間

缺點

  • 過時功能不能使用在field上,只能用在key上

  • Redis集羣架構下不適合大規模使用





List結構

List經常使用操做

咱們能夠認爲列表的左邊叫頭,右邊叫尾


List結構的操做示意圖


經常使用命令


LPUSH key value [value ...] //將一個或多個值value插入到key列表的表頭(最左邊)RPUSH key value [value ...]//將一個或多個值value插入到key列表的表尾(最右邊)LPOP key//移除並返回key列表的頭元素RPOP key//移除並返回key列表的尾元素LRANGE key start stop//返回列表key中指定區間內的元素,區間以偏移量start和stop指定
BLPOP key [key ...] timeout//從key列表表頭彈出一個元素,若列表中沒有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待BRPOP key [key ...] timeout //從key列表表尾彈出一個元素,若列表中沒有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待LLEN key //list的長度


應用場景

一、實現常見的數據結構

基於List的特性及豐富的命令能夠實現經常使用的集中數據結構:

1)Stack(棧) = LPUSH + LPOP ,FILO先入後出

結合LPUSH和LPOP命令實現棧的先進後出的特性,LPUSH從左邊入棧,LPOP從左邊出棧,先進入的後出來。至關於入口出口是一個。


2)Queue(隊列)= LPUSH + RPOP,FIFO先進先出

結合LPUSH和RPOP命令實現隊列的先進先出的特性,LPUSH從左邊入隊,RPOP從右邊出隊,先進來的先出來。至關於入口出口各在兩邊。


3)Blocking MQ(阻塞隊列)= LPUSH + BRPOP

結合LPUSH和BRPOP實現阻塞隊列,BRPOP比RPOP多了一個timeout的參數,是一個等待的最大時間,若是在這個時間內拿不到數據則返回空。


二、微博消息和微信公號消息


例如,walking本人關注了人民網、華爲中國、京港地鐵等大V,假設人民網發了一條微博,ID爲30033,我關注了他,那麼就會往個人msg這個隊列裏push這個微博ID,我在打開個人微博時,就會從這個我專屬的msg隊列裏取前幾個微博ID展現給我看,因此這個就牽涉到了幾個關鍵點:


1)人民網發了一條微博,ID爲30033,消息ID入隊

LPUSH msg:{walking-ID} 30033

2)華爲中國發微博,ID爲30055,消息入隊

LPUSH msg:{walking-ID} 30055

3)我登陸進去,會給我展現最新微博消息,那麼就從個人消息隊列裏取最新的前5條顯示在首頁

LRANGE msg:{walking-ID} 0 5






SET結構

Set經常使用操做


SADD key member [member ...]//往集合key中存入元素,元素存在則忽略,若key不存在則新建SREM key member [member ...]//從集合key中刪除元素SMEMBERS key //獲取集合key中全部元素SCARD key//獲取集合key的元素個數SISMEMBER key member//判斷member元素是否存在於集合key中SRANDMEMBER key [count]//從集合key中選出count個元素,元素不從key中刪除SPOP key [count]//從集合key中選出count個元素,元素從key中刪除


set運算操做

SINTER key [key ...] //交集運算SINTERSTORE destination key [key ..]//將交集結果存入新集合destination中SUNION key [key ..] //並集運算SUNIONSTORE destination key [key ...]//將並集結果存入新集合destination中SDIFF key [key ...] //差集運算SDIFFSTORE destination key [key ...]//將差集結果存入新集合destination中

應用場景


一、微信抽獎小程序

想必你們都用過微信裏的抽獎小程序吧,以下圖,咱們能夠點擊當即參與進行抽獎,還能夠查看全部參與人員,最後就是開獎的功能,一共三個關鍵點


咱們看一下這三個關鍵點用set數據類型怎麼實現:

1)點擊參與抽獎,則將用戶ID加入集合

SADD key {userlD}

2)查看參與抽獎全部用戶

SMEMBERS key

3)抽取count名中獎者

SRANDMEMBER key [count]//返回但不從set中剔除SPOP key [count]//返回並剔除

若是設置了一等獎二等獎三等獎...,而且每人只能得一種,則能夠用SPOP key count


二、微信微博點贊,收藏,標籤

好比walking發了一條朋友圈,有人點贊

1) 點贊 點贊就把點贊這我的的ID加到這個點讚的集合中

SADD like:{消息ID} {用戶ID}

2) 取消點贊 從集合中移除用戶ID

SREM like:{消息ID} {用戶ID}

3) 檢查用戶是否點過贊

SISMEMBER like:{消息ID} {用戶ID}

4) 獲取點讚的用戶列表

SMEMBERS like:{消息ID}

5) 獲取點贊用戶數

SCARD like:{消息ID}

Set集合運算操做的應用場景

基於Redisset集合提供的豐富的命令,咱們能夠對集合輕鬆的實現交併差的運算。例如,現有集合set1,set12,set3,元素以下:


set1:{a,b,c}set2:{a,c,e}set3:{c,d,f}

對集合進行交、並、差的運算

SINTER set1 set2 set3 //交集--> { c } SUNION set1 set2 set3 //並集--> { a,b,c,d,e,f } SDIFF set1 set2 set3 //差集--> { b }
經過這些基本操做咱們看能夠實現什麼樣的業務需求。


三、集合操做實現社交軟件關注模型

社交軟件的用戶關注模型,如QQ的好友,微博的關注,抖音、快手的關注、微信的公衆號關注,這些社交軟件都會作一個這樣的功能,那就是用戶關係的關注模型推薦,包括共同關注的人、可能認識的人、

首先看一下walking、chenmowanger、Hollis關注的人,以下:

1)walking關注的人:

walkingSet-->{chenmowanger, ImportNew, Hollis}

2) chenmowanger關注的人:

chenmowangerSet-->{walking, ImportNew, Hollis, JavaGuide}

3) Hollis關注的人:

HollisSet--> {waking, ImportNew, JavaGuide, feichao, CodeSheep}

(開玩笑,大佬們纔沒關注我,哈哈😂)


每一個人的關注列表都是一個Redis的set集合,而後當walking點到chenmowanger的主頁,就會有個區域專門展現我和二哥的一些關注狀況:

4) walking和chenmowanger共同關注:

也就是看哪些人在個人集合裏也在二哥的集合裏

//兩個集合求並集SINTER walkingSet zhangyixingSet--> {ImportNew, Hollis}

5) 我關注的人也關注他(chenmowanger):

看我關注的人的關注列表裏是否是有某我的,好比我進入chenmowanger的主頁,能夠展現我關注的人裏還有誰也關注了chenmowanger

SISMEMBER ImportNewSet chenmowangerSISMEMBER HollisSet chenmowanger

6) 我可能認識的人:

求差集,之前面這個集合爲準,看二哥關注的那些人有哪些我還沒關注,因而我就趕忙關注了JavaGuide(Guide哥)

SDIFF chenmowangerSet walkingSet->{walking, JavaGuide}

四、集合操做實現電商商品篩選


先看一下這個圖是否是很熟悉,選購手機時,有一個篩選的功能



如上圖,電商網站買手機,進到這個頁面根據各類條件搜手機,咱們想想用Redis如何實現呢?(固然了,這裏並非說人家就徹底用Redis實現這一套搜索,其實主要仍是用搜索引擎那些中間件,這裏只是說明能夠用Redis實現~)

在上架商品時維護商品,添加商品的同時把對應的商品添加到對應的set集合裏便可,以下舉例

//品牌-華爲SADD brand:huawei P30 Mate30 榮耀Play4 nova7//品牌-小米SADD brand:xiaomi mi6 mi8 mi9 mi10//品牌-iPhoneSADD brand:iPhone iphone8 iphone8plus iphoneX iphone11//操做系統-AndroidSADD os:android P30 Mate30 榮耀Play4 nova7 mi6 mi8 mi9 mi10//CPU品牌-驍龍SADD cpu:brand:xiaolong iphone8 iphone8plus iphoneX iphone11 mi6 mi8 mi9 mi10//CPU品牌-麒麟SADD cpu:brand:qilin P30 Mate30 榮耀Play4 nova7//運行內存-8GSADD ram:8G P30 Mate30 榮耀Play4 nova7 mi6 mi8 mi9 mi10 iphone8 iphone8plus iphoneX iphone11//多條件查詢 操做系統Android,CPU品牌驍龍,運行內存8GSINTER os:android cpu:brand:xiaolong ram:8G -->{mi6 mi8 mi9 mi10}


截圖更容易看:



假設咱們維護了各類品牌,手機所屬的操做系統,CPU品牌,運行內存等,那麼咱們在勾選條件查找時就能夠用勾選的各個集合求他的交集就好了。





ZSet有序集合

zset是有序的set集合,經過傳入的分值進行排序



ZSet經常使用操做

ZADD key score member [[score member]…]//往有序集合key中加入帶分值元素ZREM key member [member …] //從有序集合key中刪除元素ZSCORE key member //返回有序集合key中元素member的分值ZINCRBY key increment member//爲有序集合key中元素member的分值加上increment ZCARD key//返回有序集合key中元素個數ZRANGE key start stop [WITHSCORES]//正序獲取有序集合key從start下標到stop下標的元素ZREVRANGE key start stop [WITHSCORES]//倒序獲取有序集合key從start下標到stop下標的元素


Zset集合操做


ZUNIONSTORE destkey numkeys key [key ...] //並集計算 ZINTERSTORE destkey numkeys key [key …]//交集計算


應用場景


一、Zset集合操做實現排行榜


咱們都知道微博熱點,新聞熱榜,投票排行榜等都有一個排名的概念,以下圖百度熱榜,展現的是實時的點擊量比較高的新聞(假設這些新聞的ID爲1001-1010),每一個新聞都有一個熱點值,通常按點擊量,1001這個新聞熱點是484W,1002這個是467W,實時的,可能等會再看就不同了,那麼咱們看下用Redis咋實現。



1)點擊新聞

每次有人點擊這個新聞,那麼久ius給他的分值加1

ZINCRBY hotNews:20200722 1 1001 //新聞ID爲1001的新聞分值加一

2)展現當日排行前十

取集合中的前10個元素

ZREVRANGE hotNews:20200722 0 10 WITHSCORES

3)七日熱點榜單計算

ZUNIONSTORE hotNews:20200715-20200721 7 hotNews:20200715 hotNews:20200716... hotNews:20200721

4)展現七日排行前十

ZREVRANGE hotNews:20190813-20190819 0 10 WITHSCORES




更多應用場景

  • 微信<搖一搖><搶紅包>

  • 滴滴打車、摩拜單車<附近的車>

  • 美團和餓了麼<附近的餐館>

  • 搜索自動補全

  • 布隆過濾器






結語




本篇文章主要講了Redis五中數據類型可使用對應的命令實現的業務場景,經過咱們生活中常見的業務場景來幫助理解Redis的各類數據類型的用法,結合場景也能方便咱們更加形象的去理解和學習Redis數據類型的各類操做命令。

同時,walking也但願經過本文的引導可以激發讀者朋友對Redis數據類型應用場景的靈感,可以作作需求的時候系統設計的時候想想是否是用redis實現更好一點呢,也算是對各位的一個拋磚引玉吧。

再次聲明,本文中列舉的應用場景有些可能使用redis並非最合適的,有的只是在說明 能夠用redis去實現,但願各位可以依據本身的實際業務場景去斟酌具體怎麼設計。若有問題請幫忙指出哦。

最後但願本文的講解可以對你們有所幫助,若是有幫助請給walking一點鼓勵吧,記得  點贊❤、轉發 🤞哦~

別走開,有彩蛋 ↓ ↓ ↓







walking我的維護的這個公衆號已經有兩年了吧,起初是爲了本身總結用的,後來有人關注了,我以爲經過個人文章和分享可以幫助更多的人那就是很值得。感謝一直關注這個公衆號的朋友們 ~
雖然產量不高,我也一直在寫下去,也寫了不少文章,每篇文章都是通過幾天甚至是一個星期的打磨、推敲纔敢發出來。可是一直是不瘟不火,即使是沒有人關注,沒有人點贊,我也是會堅持下去的,由於這裏是個人積累,是我留下的痕跡~
你們有什麼建議或意見歡迎留言或私信哦~下面是我整理了兩個星期的Redis知識點,作成思惟導圖,方便你們複習,已經轉成各類格式,歡迎關注 公衆號,回覆:Redis,免費獲取



參考:
https://www.bilibili.com/video/BV1if4y1R7ns

本文分享自微信公衆號 - 編程大道(learn_code)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索