Redis基本數據類型之List

List

List是Redis的另一種基本數據類型,Redis中的List是以雙向鏈表形式存在的,key持有對鏈表頭元素和尾元素的索引。向雙向鏈表的頭部或尾部添加數據的時間複雜度是常數級別的。

基本命令

1.向列表中添加元素

既然list是雙向鏈表,那就必然支持從兩端向list中添加元素。對應的命令分別爲:
lpush key value [value …],
rpush key value [value …]
表示從左側添加元素和從右側添加元素。
命令:lrange key start stop,表示從根據開始和結束索引獲取list中的元素。

# 從左側添加元素
> lpush list a b c d 
(integer) 4
# 使用lrange命令獲取list中的元素,參數爲開始元素和結束元素的索引
> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
# 從右側添加元素x,x會被添加至a的右側
> rpush list x
(integer) 5
> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "x"

2.從列表中彈出元素

命令:lpop key 和 rpop key
分別代表從列表的左側和右側彈出一個元素。

# 從左側彈出元素
> lpop list
"d"
# 從右側彈出元素
> rpop list
"x"

應用

1.list的同向push和pop,就實現了一個棧(stack),數據的入棧與出棧滿足先進後出。
2.list的異向push和pop,則實現了一個隊列(queue),數據的入隊與出隊滿足先進先出。
3.一些場景下使用Redis的List來代替應用程序中的棧或隊列,可以在應用宕機情況下保證數據不丟失,同時還可以確保線程安全。

3.根據索引獲取和修改元素

命令:lindex key index
實現根據list的下標索引去獲取元素;
命令:lset key index value
實現根據list的下標索引去修改元素。

# list中當前元素爲:d c b a 
> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
# 獲取下標爲2的元素
> lindex list 2
"b"
# 修改下標爲2的元素
> lset list 3 xxx
OK
> lrange list
1) "d"
2) "c"
3) "xxx"
4) "a"

根據索引去操作list實際上實現了數組的功能

4.截取元素

命令:ltrim key start stop
用於截取list中索引由start至stop之間的元素

# list中當前元素爲:d c b a 
> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
# 截取第0到-1號索引的內容,即全部元素
> ltrim list 0 -1
OK
# 此時list中元素沒有發生變化
> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
# 截取第1個元素至倒數第二個元素,即取出第0個元素和最後一個元素
> ltrim list 1 -2
OK
# 此時剩餘元素爲c和b
> lrange list 0 -1
1) "c"
2) "b"

5.List中的阻塞操作

假設你需要用Redis的list構建一個基於生產者-消費者模式的隊列,生產者用lpush從一端放入數據,消費者用rpop從另一端取出數據。

問題在於:可能出現數據全部被消費,即list已經爲空的情況。此時如果使用rpop只能返回null。這種情況下消費者只能稍作等待再重試從list中獲取數據。這會導致所有對該空list的操作都是無效的,只能返回null。

爲了解決這個問題,Redis提供了rpop和lpop的阻塞版本:brpop和blpop。如果list爲空,brpop和blpop會阻塞,直到有新的元素被加入list或者達到用戶設定的超時時間。
命令格式:
blpop key [key …] timeout
brpop key [key …] timeout

這裏舉一個例子:

# 初始化一個list
> lpush list 5 4 3 2 1
(integer) 7
> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "c"
7) "b"
# 使用blpop以阻塞方式從list左側獲取一個元素,超時時間爲5秒,返回key和對應獲取到的值
> blpop list 5
1) "list"
2) "1"

blpop和brpop命令可以添加多個list作爲key,返回的數據格式爲一個包含兩個元素的數組。顯示第一個返回的list的key及對應值。

6.key的自動創建與銷燬

根據Redis官方的介紹:

It is Redis’ responsibility to delete keys when lists are left empty, or to create an empty list if the key does not exist and we are trying to add elements to it.

Redis是個有責任心的組件,如果一個list中已經沒有元素了,該key會自動銷燬;如果向一個未被創建的key中添加元素,Redis會自動創建一個空的list。

總結下來有一下三點:
1.當我們向一個聚合數據類型中添加元素時,如果目標key還不存在,Redis會在添加元素之前創建一個空的key;例如:

# 刪除名爲list的key
> del list
(integer) 1
> lpush list 1 2 3
(integer) 3

2.如果從一個聚合數據類型中取完數據,該value已經是空的了,那麼這個key會自動被銷燬(Stream類型的數據除外),如:

> lpush list 1 2 
(integer) 2
> exists list
(integer) 1
# 此時將list中全部元素彈出
> lpop list
"2"
> lpop list
"1"
# 再次判斷key是否存在,此時key已被銷燬
> exists list
(integer) 0

3.針對已爲空的list調用如llen這樣的只讀命令或移除元素的命令時,Redis會製造一種假象,彷彿一個指向空list的key還存在,並正確返回命令的結果,如:

# 刪除key
> del list
(integer) 0
# 獲取list的長度
> llen list
(integer) 0
# 從list中獲取元素
> lpop list
(nil)

以上就是Redis中List的基本概念與常用命令,大家是否學到了呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章