zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

redis数据结构之链表(linked-list)

2023-09-27 14:22:26 时间

链表结构在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就会对对应的链表加锁,加锁的结果就是其他的进程就不能在读取或写入该链表,只能等待操作结束后才能对该链表进行操作。这样就保证了数据的安全和一致性。
万物都有利有弊,虽然阻塞能保证数据的安全和一致性,但是这样就会付出其他线程等待,线程环境切换等代价,从而导致系统的并发能力下降。