redis中List列表常見(jiàn)命令及使用場(chǎng)景
前言
列表類型是用來(lái)存儲(chǔ)多個(gè)有序的字符串,如圖2-19所示,a、b、C、d、e五個(gè)元素從左到右組成了一個(gè)有序的列表,列表中的每個(gè)字符串稱為元素(element) ,一個(gè)列表最多可以存儲(chǔ)2^32 - 1 個(gè)元素。在Redis中,可以對(duì)列表兩端插入(push) 和彈出(pop) ,還可以獲取指定范圍的元素列表、
獲取指定索引下標(biāo)的元素等(如圖2-19和圖2-20所示)。列表是一種比較靈活的數(shù)據(jù)結(jié)構(gòu),它可以充當(dāng)棧和隊(duì)列的角色,在實(shí)際開(kāi)發(fā)上有很多應(yīng)用場(chǎng)景。
圖2-19列表兩端插入和彈出操作
圖2-20列表的獲取、刪除等操作
列表類型的特點(diǎn):
第一、列表中的元素是有序的,這意味著可以通過(guò)索引下標(biāo)獲取某個(gè)元素或者某個(gè)范圍的元素列表,例如要獲取圖2-20的第5個(gè)元素,可以執(zhí)行l(wèi)index user:1:messages 4或者倒數(shù)第1個(gè)元素,lindex user:1:messages -1就可以得到元素e。
第二、區(qū)分獲取和刪除的區(qū)別,例如圖2-20中的lrem 1 b是從列表中把從左數(shù)遇到的前1個(gè)b元素刪除,這個(gè)操作會(huì)導(dǎo)致列表的長(zhǎng)度從5變成4;但是執(zhí)行l(wèi)index 4只會(huì)獲取元素,但列表長(zhǎng)度是不會(huì)變化
的。
第三、列表中的元素是允許重復(fù)的,例如圖2-21中的列表中是包含了兩個(gè)a元素的。
圖2-21列表中允許有重復(fù)元素
1.常見(jiàn)命令
LPUSH
將一個(gè)或者多個(gè)元素從左側(cè)放入(頭插)到list中。
語(yǔ)法:
LPUSH key element [element ...]
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度:只插入一個(gè)元素為0(1), 插入多個(gè)元素為O(N), N為插入元素個(gè)數(shù).
返回值:插入后list的長(zhǎng)度。
示例:
redis> LPUSH mylist "world" (integer) 1 redis> LPUSH mylist "hello" (integer) 2 redis> LRANGE mylist 0 -1 1) "hello" 2) "world"
LPUSHX
在key存在時(shí),將-個(gè)或者多個(gè)元素從左側(cè)放入(頭插)到list中。不存在,直接返回
語(yǔ)法:
LPUSHX key element [element ...]
命令有效版本: 2.0.0之后
時(shí)間復(fù)雜度:只插入一個(gè)元素為0(1), 插入多個(gè)元素為0(N), N為插入元素個(gè)數(shù).
返回值:插入后list的長(zhǎng)度。
示例:
redis> LPUSH mylist "World" (integer) 1 redis> LPUSHX mylist "Hello" (integer) 2 redis> LPUSHX myotherlist "Hello" (integer) 0 redis> LRANGE mylist 0 -1 1) "Hello" 2) "World" redis> LRANGE myotherlist 0 -1 (empty array)
RPUSH
將一個(gè)或者多個(gè)元素從右側(cè)放入(尾插)到list 中。
語(yǔ)法:
RPUSH key element [element ...]
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度:只插入一個(gè)元素為0(1), 插入多個(gè)元素為O(N), N為插入元素個(gè)數(shù).
返回值:插入后list的長(zhǎng)度。
示例:
redis> RPUSH mylist "world" (integer) 1 redis> RPUSH mylist "hello" (integer) 2 redis> LRANGE mylist 0 -1 1) "world" 2) "hello"
RPUSHX
在key存在時(shí),將一個(gè)或者多個(gè)元素從右側(cè)放入(尾插)到list中。
語(yǔ)法:
RPUSHX key element [element ...]
命令有效版本: 2.0.0之后
時(shí)間復(fù)雜度:只插入一個(gè)元素為0(1),插入多個(gè)元素為O(N), N為插入元素個(gè)數(shù).
返回值:插入后list的長(zhǎng)度。
示例:
redis> RPUSH mylist "World" (integer) 1 redis> RPUSHX mylist "Hello" (integer) 2 redis> RPUSHX myotherlist "Hello" (integer) 0 redis> LRANGE mylist 0 -1 1) "World" 2) "Hello" redis> LRANGE myotherlist 0 -1 (empty array)
LRANGE
獲取從start到end區(qū)間的所有元素,左閉右閉。
語(yǔ)法:
LRANGE key start stop
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度: O(N)
返回值:指定區(qū)間的元素。
示例:
redis> RPUSH mylist "one" (integer) 1 redis> RPUSH mylist "two" (integer) 2 redis> RPUSH mylist "three" (integer) 3 redis> LRANGE mylist 0 0 1) "one" redis> LRANGE mylist -3 2 1) "one" 2) "two" 3) "three" redis> LRANGE mylist -100 100 1) "one" 2) "two" 3) "three" redis> LRANGE mylist 5 10 (empty array)
LPOP
從list左側(cè)取出元素(即頭刪)。
語(yǔ)法:
LPOP key
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度: O(1)
返回值:取出的元素或者nilo
示例:
redis> RPUSH mylist "one" "two" "three" "four" "five" (integer) 5 redis> LPOP mylist "one" redis> LPOP mylist "two" redis> LPOP mylist "three" redis> LRANGE mylist 0 -1 1) "four" 2) "five"
RPOP
從list右側(cè)取出元素(即尾刪)。
語(yǔ)法:
RPOP key
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度: 0(1)
返回值:取出的元素或者nil。
示例:
redis> RPUSH mylist "one" "two" "three" "four" "five" (integer) 5 redis> RPOP mylist "five" redis> LRANGE mylist 0 -1 1) "one" 2) "two" 3) "three" 4) "four"
LINDEX
獲取從左數(shù)第index位置的元素。
語(yǔ)法:
LINDEX key index
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度: O(N)
返回值:取出的元素或者nil。
示例:
redis> LPUSH mylist "World" (integer) 1 redis> LPUSH mylist "Hello" (integer) 2 redis> LINDEX mylist 0 "Hello" redis> LINDEX mylist -1 "World" redis> LINDEX mylist 3 (nil)
LINSERT
在特定位置插入元素。
語(yǔ)法:
LINSERT key <BEFORE | AFTER> pivot element
命令有效版本: 2.2.0之后
時(shí)間復(fù)雜度: O(N)
返回值:插入后的list長(zhǎng)度。
示例:
redis> RPUSH mylist "Hello" (integer) 1 redis> RPUSH mylist "World" (integer) 2 redis> LINSERT mylist BEFORE "World" "There" (integer) 3 redis> LRANGE mylist 0 -1 1) "Hello" 2) "There" 3) "World"
LLEN
獲取list長(zhǎng)度。
語(yǔ)法:
LLEN key
命令有效版本: 1.0.0之后
時(shí)間復(fù)雜度: 0(1)
返回值: list 的長(zhǎng)度。
示例:
redis> LPUSH mylist "World" (integer) 1 redis> LPUSH mylist "Hello" (integer) 2 redis> LLEN mylist (integer) 2
阻塞版本命令
blpop和brpop是lpop和rpop的阻塞版本,和對(duì)應(yīng)非阻塞版本的作用基本一致,除了:
●在列表中有元素的情況下,阻塞和非阻塞表現(xiàn)是一致的。但如果列表中沒(méi)有元素,非阻塞版本會(huì)理解返回nil,但阻塞版本會(huì)根據(jù)timeout,阻塞一段時(shí)間, 期間Redis可以執(zhí)行其他命令,但要求執(zhí)行該命令的客戶端會(huì)表現(xiàn)為阻塞狀態(tài)(如圖2-22所示)。
●命令中如果設(shè)置了多個(gè)鍵,那么會(huì)從左向右進(jìn)行遍歷鍵,一旦有一個(gè)鍵對(duì)應(yīng)的列表中可以彈出元素,命令立即返回。
●如果多個(gè)客戶端同時(shí)多一個(gè)鍵執(zhí)行pop,則最先執(zhí)行命令的客戶端會(huì)得到彈出的元素。
圖2-22阻塞版本的blpop和非阻塞版本lpop的區(qū)別
BLPOP
LPOP的阻塞版本。
語(yǔ)法:
BLPOP key [key ...] timeout
命令有效版本: 1.0.0 之后
時(shí)間復(fù)雜度: 0(1)
返回值:取出的元素或者nil。
示例:
redis> EXISTS list1 list2 (integer) 0 redis> RPUSH list1 a b c (integer) 3 redis> BLPOP list1 list2 0 1) "list1" 2) "a"
BRPOP
RPOP的阻塞版本。.
語(yǔ)法:
BRPOP key [key ...] timeout
命令有效版本: 1.0.0 之后
時(shí)間復(fù)雜度: 0(1)
返回值:取出的元素或者nil。
示例:
redis> DEL list1 list2 (integer) 0 redis> RPUSH list1 a b c (integer) 3 redis> BRPOP list1 list2 0 1) "list1" 2) "c"
命令小結(jié)
有關(guān)列表的命令已經(jīng)介紹完畢,表2-5是這些命令的作用和時(shí)間復(fù)雜度,開(kāi)發(fā)人員可以參考。
內(nèi)部編碼
列表類型的內(nèi)部編碼有兩種:
●ziplist (壓縮列表) : 當(dāng)列表的元素個(gè)數(shù)小于list-max-ziplist-entries配置(默認(rèn)512個(gè)),同時(shí)列表中每個(gè)元素的長(zhǎng)度都小于list-max-ziplist-value配置(默認(rèn)64字節(jié))時(shí),Redis 會(huì)選用ziplist來(lái)作為列表的內(nèi)部編碼實(shí)現(xiàn)來(lái)減少內(nèi)存消耗。
●linkedlist (鏈表) :當(dāng)列表類型無(wú)法滿足ziplist的條件時(shí),Redis會(huì)使用linkedlist 作為列表的內(nèi)部實(shí)現(xiàn)。
1)當(dāng)元素個(gè)數(shù)較少且沒(méi)有大元素時(shí),內(nèi)部編碼為ziplist:
127.0.0.1:6379> rpush listkey e1 e2 e3 OK 127.0.0.1:6379> object encoding listkey "ziplist"
2)當(dāng)元素個(gè)數(shù)超過(guò)512時(shí),內(nèi)部編碼為linkedlist:
127.0.0.1:6379> rpush listkey e1 e2 e3 ... 省略 e512 e513 OK 127.0.0.1:6379> object encoding listkey "linkedlist"
3)當(dāng)某個(gè)元素的長(zhǎng)度超過(guò)64字節(jié)時(shí),內(nèi)部編碼為linkedlist:
127.0.0.1:6379> rpush listkey "one string is bigger than 64 bytes ... 省略 ..." OK 127.0.0.1:6379> object encoding listkey "linkedlist"
2.使用場(chǎng)景
消息隊(duì)列
如圖2-22所示,Redis 可以使用lpush + brpop命令組合實(shí)現(xiàn)經(jīng)典的阻塞式生產(chǎn)者消費(fèi)者模型隊(duì)列,生產(chǎn)者客戶端使用lpush從列表左側(cè)插入元素,多個(gè)消費(fèi)者客戶端使用brpop命令阻塞式地從隊(duì)列中"爭(zhēng)搶"隊(duì)首元素。通過(guò)多個(gè)客戶端來(lái)保證消費(fèi)的負(fù)載均衡和高可用性。
分頻道的消息隊(duì)列
如圖2-23所示,Redis 同樣使用lpush + brpop命令,但通過(guò)不同的鍵模擬頻道的概念,不同的消費(fèi)者可以通過(guò)brpop不同的鍵值,實(shí)現(xiàn)訂閱不同頻道的理念。
圖2-23 Redis分頻道阻塞消息隊(duì)列模型
微博Timeline
每個(gè)用戶都有屬于自己的Timeline (微博列表),現(xiàn)需要分頁(yè)展示文章列表。此時(shí)可以考慮使用列表,因?yàn)榱斜聿坏怯行虻?,同時(shí)支持按照索引|范圍獲取元素。
1)每篇微博使用哈希結(jié)構(gòu)存儲(chǔ),例如微博中3個(gè)屬性: title、 timestamp、 content:
hmset mblog:1 title xx timestamp 1476536196 content xxxxx ... hmset mblog:n title xx timestamp 1476536196 content xxxxx
2)向用戶Timeline添加微博,user:<uid>:mblogs 作為微博的鍵:
lpush user:1:mblogs mblog:1 mblog:3 ... lpush user:k:mblogs mblog:9
3)分頁(yè)獲取用戶的Timeline,例如獲取用戶1的前10篇微博:
keylist = lrange user:1:mblogs 0 9 for key in keylist { hgetall key }
此方案在實(shí)際中可能存在兩個(gè)問(wèn)題:
1. 1 + n問(wèn)題。即如果每次分頁(yè)獲取的微博個(gè)數(shù)較多,需要執(zhí)行多次hgetall操作,此時(shí)可以考慮使用pipeline (流水線)模式批量提交命令,或者微博不采用哈希類型,而是使用序列化的字符串類型,使用mget獲取。
2.分裂獲取文章時(shí),lrange 在列表兩端表現(xiàn)較好,獲取列表中間的元素表現(xiàn)較差,此時(shí)可以考慮將列表做拆分。
選擇列表類型時(shí),請(qǐng)參考:
- 同側(cè)存取(lpush + lpop或者rpush + rpop)為棧
- 異側(cè)存取(Ipush + rpop或者rpush + lpop)為隊(duì)列
總結(jié)
到此這篇關(guān)于redis中List列表常見(jiàn)命令及使用場(chǎng)景的文章就介紹到這了,更多相關(guān)redis List列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Linux、Windows下Redis的安裝即Redis的基本使用詳解
Redis是一個(gè)基于內(nèi)存的key-value結(jié)構(gòu)數(shù)據(jù)庫(kù),Redis 是互聯(lián)網(wǎng)技術(shù)領(lǐng)域使用最為廣泛的存儲(chǔ)中間件,這篇文章主要介紹了Linux、Windows下Redis的安裝即Redis的基本使用詳解,需要的朋友可以參考下2022-09-09redis實(shí)現(xiàn)延時(shí)隊(duì)列的兩種方式(小結(jié))
這篇文章主要介紹了redis實(shí)現(xiàn)延時(shí)隊(duì)列的兩種方式(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04簡(jiǎn)介L(zhǎng)ua腳本與Redis數(shù)據(jù)庫(kù)的結(jié)合使用
這篇文章主要介紹了簡(jiǎn)介L(zhǎng)ua腳本與Redis數(shù)據(jù)庫(kù)的結(jié)合使用,Redis是基于主存的高性能數(shù)據(jù)庫(kù),需要的朋友可以參考下2015-06-06Redis如何使用HyperLogLog的實(shí)現(xiàn)
本文主要介紹了Redis如何使用HyperLogLog的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Redis與數(shù)據(jù)庫(kù)數(shù)據(jù)一致性的原因及解決方案
Redis作為一種高效的鍵值對(duì)存儲(chǔ)系統(tǒng),常用于緩存數(shù)據(jù)庫(kù)減少IO操作,下面這篇文章主要介紹了Redis與數(shù)據(jù)庫(kù)數(shù)據(jù)一致性的原因及解決方案,文中介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04Windows環(huán)境下打開(kāi)Redis閃退的解決方案
每次使用完Redis后,我們習(xí)慣性的動(dòng)作是直接叉掉doc頁(yè)面,這樣導(dǎo)致的結(jié)果是Redis在后臺(tái)繼續(xù)運(yùn)行,沒(méi)有關(guān)閉,所以當(dāng)再次打開(kāi)的時(shí)候直接閃退,文中有詳細(xì)的解決方案,需要的朋友可以參考下2024-03-03