Redis 存储数据的 Value 可以是一个 String 列表类型数据。即该列表中的每个元素均为String 类型数据。列表中的数据会按照插入顺序进行排序。不过,该列表的底层实际是一个无头节点的双向链表,所以对列表表头与表尾的操作性能较高,但对中间元素的插入与删除的操作的性能相对较差。
# 一、lpush/rpush
● 格式:LPUSH key value [value ...] 或 RPUSH key value [value ...]
● 功能:将一个或多个值 value 插入到列表 key 的表头/表尾(表头在左表尾在右)
● 说明:如果有多个 value 值,对于 lpush 来说,各个 value 会按从左到右的顺序依次插入到表头;对于 rpush 来说,各个 value 会按从左到右的顺序依次插入到表尾。如果 key不存在,一个空列表会被创建并执行操作。当 key 存在但不是列表类型时,返回一个错误。执行成功时返回列表的长度。
# 二、llen
● 格式:LLEN key
● 功能:返回列表 key 的长度。
● 说明:如果 key 不存在,则 key 被解释为一个空列表,返回 0 。如果 key 不是列表类型,返回一个错误。
# 三、lindex
● 格式:LINDEX key index
● 功能:返回列表 key 中,下标为 index 的元素。列表从 0 开始计数。
● 说明:如果 index 参数的值不在列表的区间范围内(out of range),返回 nil。
# 四、lset
● 格式:LSET key index value
● 功能:将列表 key 下标为 index 的元素的值设置为 value 。
● 说明:当 index 参数超出范围,或对一个空列表(key 不存在)进行 LSET 时,返回一个错误。
# 五、lrange
● 格式:LRANGE key start stop
● 功能:返回列表 key 中指定区间[start, stop]内的元素,即包含两个端点。
● 说明:List 的下标从 0 开始,即以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2表示列表的倒数第二个元素,以此类推。超出范围的下标值不会引起错误。如果 start 下标比列表的最大下标 还要大,那么 LRANGE 返回一个空列表。如果 stop下标比最大下标还要大,Redis 将 stop 的值设置为最大下标。
# 六、lpushx 与 rpushx
● 格式:LPUSHX key value 或 RPUSHX key value
● 功能:将值 value 插入到列表 key 的表头/表尾,当且仅当 key 存在并且是一个列表。
● 说明:当 key 不存在时,命令什么也不做。若执行成功,则输出表的长度。
# 七、linsert
● 格式:LINSERT key BEFORE|AFTER pivot value
● 功能:将值 value 插入到列表 key 当中,位于元素 pivot 之前或之后。
● 说明:当 pivot 元素不存在于列表中时,不执行任何操作,返回-1;当 key 不存在时,key 被视为空列表,不执行任何操作,返回 0;如果 key不是列表类型,返回一个错误;如果命令执行成功,返回插入操作完成之后,列表的长度。
# 八、lpop / rpop
● 格式:LPOP key [count] 或 RPOP key [count]
● 功能:从列表 key 的表头/表尾移除 count 个元素,并返回移除的元素。count 默认值 1
● 说明:当 key 不存在时,返回 nil。
# 九、blpop / brpop
● 格式:BLPOP key [key ...] timeout 或 BRPOP key [key ...] timeout
● 功能:BLPOP/BRPOP 是列表的阻塞式(blocking)弹出命令。它们是 LPOP/RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被BLPOP/BRPOP 命令阻塞,直到等待 timeout 超时或发现可弹出元素为止。当给定多个 key 参数时,按参数 key的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。timeout 为阻塞时长,单位为秒,其值若为 0,则表示只要没有可弹出元素,则一直阻塞。
● 说明:假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。反之,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
# 十、rpoplpush
● 格式:RPOPLPUSH source destination
● 功能:命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
◆ 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
◆ 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。如果 source 不存在,值 nil被返回,并且不执行其他动作。如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列 表的旋转(rotation)操作。
# 十一、brpoplpush
● 格式:BRPOPLPUSH source destination timeout
● 功能:BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。当列表source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。timeout为阻塞时长,单位为秒,其值若为 0,则表示只要没有可弹出元素,则一直阻塞。
● 说明:假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。
# 十二、lrem
● 格式:LREM key count value
● 功能:根据参数 count 的值,移除列表中与参数 value 相等的元素。count 的值可以是以下几种:
◆ count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
◆ count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
◆ count = 0 : 移除表中所有与 value 相等的值。
● 说明:返回被移除元素的数量。当 key 不存在时, LREM 命令返回 0 ,因为不存在的 key 被视作空表(empty list)。
# 十三、ltrim
● 格式:LTRIM key start stop
● 功能:对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
● 说明:下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。当 key 不是列表类型时,返回一个错误。如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,或者 start > stop , LTRIM 返回一个空列表,因为 LTRIM 已经将整个列表清空。如果 stop 下标比 end 下标还要大,Redis 将stop 的值设置为 end。
# 十四、应用场景
Value 为 List 类型的应用场景很多,主要是通过构建不同的数据结构来实现相应的业务功能。这里仅对这些数据结构的实现方式进行总结,不举具体的例子。
# 1、栈
通过 lpush + lpop 可以实现栈数据结构效果:先进后出。通过 lpush 从列表左侧插入数据,通过 lpop 从列表左侧取出数据。当然,通过 rpush + rpop也可以实现相同效果,只不过操作的是列表右侧。
# 2、队列
通过 lpush + rpop 可以实现队列数据结构效果:先进先出。通过 lpush 从列表左侧插入数据,通过 rpop 从列表右侧取出数据。当然,通过 rpush + lpop 也可以实现相同效果,只不过操作的方向正好相反。
# 3、阻塞式消息队列
通过 lpush + brpop 可以实现阻塞式消息队列效果。作为消息生产者的客户端使用 lpush从列表左侧插入数据,作为消息消费者的多个客户端使用 brpop阻塞式“抢占”列表尾部数据进行消费,保证了消费的负载均衡与高可用性。brpop 的 timeout 设置为 0,表示只要没有数据可弹出,就永久阻塞。
# 4、动态有限集合
通过 lpush + ltrim 可以实现有限集合。通过lpush 从列表左侧向列表中添加数据,通过 ltrim保持集合的动态有限性。像企业的末位淘汰、学校的重点班等动态管理,都可通过这种动态有限集合来实现。当然,通过rpush + ltrim 也可以实现相同效果,只不过操作的方向正好相反。