一、列表對象概述
? ? ? 列表類型是用來存儲多個有序的字符串,一個列表最多可以存儲多個元素。列表是一種比較靈活的數據結構,它可以充當棧和隊列的角色,在實際開發上有很多應用場景
特點:
一個列表可以存儲多個字符串,相同元素可以重復出現
列表中的元素是有序的,根據元素的插入、刪除順序對元素進行排序
優點:可以包含多個字符串值,使得用戶可以將數據集中在同一個地方。
二、命令
常用命令?
命令 | 用例和描述 | |
RPUSH | RPUSH? key-namevaluelvalue...]-將一個或多個值推入列表的右端 | |
LPUSH | LPUSH? key-nanevalue[value...]-將一個或多個值推入列衷的左蹦 | |
RPOP | RPOP? key-name- 移除并返回剛農聶石瑞的元素 | |
LPOP | LPOP? ?key-name- 移除并返回列農最左瑞印元素 | |
LINDEX | LINDEX? key-nameoffset--返回列表中偏移量為offset的元素 | |
LRANGE | LRANGE key-name start? end-返回列表從start偏移量到end偏移量范圍內的所有元素. 其中偏移量為start和偏移量為end的元素也會包否在被返回的元素之內 | |
LTRIM | LTRIM key-name start end-對列表進行修剪,只保留從start偏移量到end偏移量范圍 內的元素,其中俯移量為start和偏移量為end的元景也會被床出 |
linsert:
linsert命令會從列表中找到等于pivot的元素,在其前(before)或者后 (after)插入一個新的元素value
linsert key before|after pivot value
例如下面操作會在列表的元素a前插入C++:
llen:
獲取列表長度
llen key
lrem:刪除指定元素。lrem命令會從列表中找到等于value的元素進行刪除,根據count的不同分為三種情況:
count>0,從左到右,刪除最多count個元素
count<0,從右到左,刪除最多count絕對值個元素
count=0,刪除所有
lrem key count value
?
lset:修改指定索引下標的元素
lset key index newValue
?
lrange注意事項:
第一,索引下標從左到右分別是0到N-1,但是從右到左分別是-1到-N
?第二,lrange中的end選項包含了自身,這個和很多編程語言不包含end不太相同
其他演示案例:
接上
接上
其他命令
命令 | 用例和描述 |
BLPOP | BLPOP key-name [key-name?...]timeout———從第一個非空列表中彈出位升最左端 1元素, |
BRPOP | BRPOP key-name [key-name ...]timeout—從第一個非空列表中彈出位扌最右端的 元素, 或者在timeout秒之內阻塞并等待中彈出的元素出現 |
RPOPLPUSH | RPOPLPUSH source-key dest-key 從source-key列表中彈出位于最右端的元素,然后 將這個元素推入dest-key列表的最左端. 并向用戶返回這個元素 |
BRPOPLPUSH | BRPOPLPUSH source-key dest-key timeout——從source-key列表中彈出位于最右端 元素,然后將這個元素推入dest-key列表的最左端,并向用戶返回這個元素,如果source-key 為空,那么在timeout秒之內阻塞并等特可彈出的元素出現 |
在Redis隊列的場景下,這些命令會非常有用
對于阻塞彈出命令和彈出并推入命令,最常用的就是消息傳遞和任務隊列
BLPOP命令演示案例
先用BLPOP命令阻塞等待new_list鍵中有值出現
在右側客戶端中向new_list中壓入一個元素,可以看到左側返回
BRPOPLPUSH命令演示案例
左側等待source_list中有鍵值可以移動到dest_list中
右側向source_list壓入值,左側看到成功返回
查看source_list中的值,可以看到沒有了(已經移動到dest_list列表中了),右側查看dest_list列表
列表命令的復雜度:
三、內部編碼
列表類型的內部編碼有兩種:
ziplist(壓縮列表):當列表的元素個數小于list-max-ziplist-entries配置 (默認512個),同時列表中每個元素的值都小于list-max-ziplist-value配置時 (默認64字節),Redis會選用ziplist來作為列表的內部實現來減少內存的使 用
linkedlist(鏈表):當列表類型無法滿足ziplist的條件時,Redis會使用 linkedlist作為列表的內部實現。
Redis3.2版本提供了quicklist內部編碼,簡單地說它是以一個ziplist為節點的linkedlist,它結合了ziplist和linkedlist兩者的優勢,為列表類型提供了一 種更為優秀的內部編碼實現.
四、使用場景
①消息隊列
如下圖所示,Redis的lpush+brpop命令組合即可實現阻塞隊列,生產者客戶端使用lrpush從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞式的“搶”列表尾部的元素,多個客戶端保證了消費的負載均衡和高可用性
②文章列表
每個用戶有屬于自己的文章列表,現需要分頁展示文章列表。此時可以考慮使用列表,因為列表不但是有序的,同時支持按照索引范圍獲取元素
①每篇文章使用哈希結構存儲,例如每篇文章有3個屬性title、 timestamp、content:
hmset acticle:1 title xx timestamp 1476536196 content xxxx
...
hmset acticle:k title yy timestamp 1476512536 content yyyy
...
②向用戶文章列表添加文章,user:{id}:articles作為用戶文章列表的鍵:
lpush user:1:acticles article:1 article3
...
lpush user:k:acticles article:5
...
③分頁獲取用戶文章列表,例如下面偽代碼獲取用戶id=1的前10篇文章:
articles = lrange user:1:articles 0 9
for article in {articles}
hgetall {article}
使用列表類型保存和獲取文章列表會存在兩個問題:
第一,如果每次分 頁獲取的文章個數較多,需要執行多次hgetall操作,此時可以考慮使用Pipeline(后面文章有介紹)批量獲取,或者考慮將文章數據序列化為字符串類 型,使用mget批量獲取
第二,分頁獲取文章列表時,lrange命令在列表兩 端性能較好,但是如果列表較大,獲取列表中間范圍的元素性能會變差,此 時可以考慮將列表做二級拆分,或者使用Redis3.2的quicklist內部編碼實現, 它結合ziplist和linkedlist的特點,獲取列表中間范圍的元素時也可以高效完成
實際上列表的使用場景很多,在選擇時可以參考以下口訣:
lpush+lpop=Stack(棧)
lpush+rpop=Queue(隊列)
lpsh+ltrim=Capped Collection(有限集合)
lpush+brpop=Message Queue(消息隊列)