鏈表結構在redis中可以存儲多個字符串,並且是有序的,能夠存儲2的32次方-1個節點(超過40億個節點),此外鏈表還是雙向的,因此可以從左到右或者從右到左進行遍歷它存儲的節點。
鏈表結構的優點是插入和刪除非常方便快速,而查詢遍歷則性能非常低下。新增或者刪除節點只需要改變節點的指向指針即可,而查詢遍歷則需要挨個進行遍歷對比。
由鏈表特性可知,鏈表的使用是要區分場景的,在經常需要插入和刪除的列表數據的場景下使用鏈表是非常快速方便的,因為它可以在不移動其他節點的情況下完成插入和刪除。而對於經常需要查詢的場景則不適宜用鏈表進行操作。因為是雙向鏈表結構,所以redis鏈表命令分為左操作(從左到右)和右操作(從右到左)兩種命令。
命令如下表所示:
命令 | 說明 | 備注 |
---|---|---|
lpush key node1[node2....] | 把節點node1加入到鏈表最左邊 | 如果是node1、node2、node3這樣加入,則鏈表開頭從左到右的順序是node3、node2、node1 |
rpush key node1[node2....] | 把節點node1加入到鏈表最右邊 | 如果是node1、node2、node3這樣加入,則鏈表開頭從左到右的順序是node1、node2、node3 |
lindex key index | 讀取下標為index的節點 | 返回節點字符串,從0開始算 |
llen key | 求鏈表的長度 | |
lpop key | 刪除左邊第一個節點並將其返回 | |
rpop key | 刪除右邊第一個節點並將其返回 | |
linsert key before|after pivot node | 插入一個節點node,並且可以指定在值pivot的節點的前面或者后面 | 如果list不存在則報錯,如果沒有值為對應的pivot也會插入失敗,返回-1 |
lpushx list node | 如果存在key為list的鏈表,則插入節點node,並且作為從左到右的第一個節點 | 如果list不存在則失敗 |
rpushx list node | 如果存在key為list的鏈表,則插入節點node,並且作為從左到右的最后一個節點 | 如果list不存在則失敗 |
lrange list start end | 截取列表,獲取鏈表list從start下標到end下標的節點值 | 包括start和end下標的值 |
lrem list count value | 如果count為0,則刪除所有值等於value的節點;如果count不為0,則先對count取絕對值,假設為abs,然后從左到右刪除不大於abs個等於value的節點 | count為整數,如果為負數,redis則先對其取絕對值,然后傳遞到后台進行操作 |
lset key index value | 設置列表下標為index的節點的值為node | |
ltrim key start stop | 裁剪列表,只保留從start到stop區間的節點,其余的都刪除掉 | 包含start和stop下標的節點會保留 |
注意:其中l表示左操作,r表示右操作。
操作示例如下:
值得注意的是以上這些操作鏈表的命令都不是進程安全的,因為當我們操作這些命令的時候,其他redis客戶端也可能在操作同一個鏈表,這樣就會造成並發數據安全和一致性問題。為了解決這個並發數據不安全和不一致問題,redis提供了鏈表的阻塞命令,他們在運行的時候會給鏈表加鎖,以保證操作鏈表命令的安全性。
如下表所示:
命令 | 說明 | 備注 |
---|---|---|
blpop key timeout | 刪除並獲取鏈表的第一個元素,如果列表沒有元素會阻塞列表直到超時或者有元素可被刪除為止 | 相對於lpop命令,它的操作是進程安全的 |
brpop key timeout | 刪除並獲取鏈表的最后一個元素,如果列表沒有元素會阻塞列表直到超時或者有元素可被刪除為止 | 相對於rpop命令,它的操作是進程安全的 |
rpoplpush key src dest | 按照從左到右的順序,刪除一個鏈表的最后一個元素並插入到目標鏈表的最左邊 | 不能設置超時時間 |
brpoplpush key src dest timeout | 按照從左到右的順序,刪除一個鏈表的最后一個元素並插入到目標鏈表的最左邊,並可以設置超時時間 | 可設置超時時間 |
當使用以上命令時,redis就會對對應的鏈表加鎖,加鎖的結果就是其他的進程就不能在讀取或寫入該鏈表,只能等待操作結束后才能對該鏈表進行操作。這樣就保證了數據的安全和一致性。
萬物都有利有弊,雖然阻塞能保證數據的安全和一致性,但是這樣就會付出其他線程等待,線程環境切換等代價,從而導致系統的並發能力下降。