共计 3094 个字符,预计需要花费 8 分钟才能阅读完成。
一、前言
Redis 提供了 5 种数据类型:String(字符串)、Hash(哈希)、List(列表)、Set(汇合)、Zset(有序汇合),了解每种数据类型的特点对于 redis 的开发和运维十分重要。
<p align=”right”> 原文解析 </p>
Redis 中的 list 是咱们常常应用到的一种数据类型,依据应用形式的不同,能够利用到很多场景中。
二、操作命令
List 数据类型在 Redis 中的相干命令::
命令 | 形容 | 用法 |
---|---|---|
LPUSH | 1. 将一个或多个值 value 插入到列表 key 的表头 2. 如果有多个 value 值,那么各个 value 值按从左到右的程序顺次插入表头 3.key 不存在,一个空列表会被创立并执行 LPUSH 操作 4.key 存在但不是列表类型,返回谬误 |
LPUSH key value [value …] |
LPUSHX | 1. 将值 value 插入到列表 key 的表头,当且仅当 key 存在且为一个列表 2.key 不存在时,LPUSHX 命令什么都不做 |
LPUSHX key value |
LPOP | 1. 移除并返回列表 key 的头元素 | LPOP key |
LRANGE | 1. 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定 2.start 和 stop 都以 0 位底 3. 可应用正数下标,- 1 示意列表最初一个元素,- 2 示意列表倒数第二个元素,以此类推 4.start 大于列表最大下标,返回空列表 5.stop 大于列表最大下标,stop= 列表最大下标 |
LRANGE key start stop |
LREM | 1. 依据 count 的值,移除列表中与 value 相等的元素 2.count>0 示意从头到尾搜寻,移除与 value 相等的元素,数量为 count 3.count<0 示意从从尾到头搜寻,移除与 value 相等的元素,数量为 count 4.count= 0 示意移除表中所有与 value 相等的元素 |
LREM key count value |
LSET | 1. 将列表 key 下标为 index 的元素值设为 value 2.index 参数超出范围,或对一个空列表进行 LSET 时,返回谬误 |
LSET key index value |
LINDEX | 1. 返回列表 key 中,下标为 index 的元素 | LINDEX key index |
LINSERT | 1. 将值 value 插入列表 key 中,位于 pivot 后面或者前面 2.pivot 不存在于列表 key 时,不执行任何操作 3.key 不存在,不执行任何操作 |
LINSERT key BEFORE AFTER pivot value |
LLEN | 1. 返回列表 key 的长度 2.key 不存在,返回 0 |
LLEN key |
LTRIM | 1. 对一个列表进行修剪,让列表只返回指定区间内的元素,不存在指定区间内的都将被移除 | LTRIM key start stop |
RPOP | 1. 移除并返回列表 key 的尾元素 | RPOP key |
RPOPLPUSH | 在一个原子工夫内,执行两个动作: 1. 将列表 source 中最初一个元素弹出并返回给客户端 2. 将 source 弹出的元素插入到列表 desination,作为 destination 列表的头元素 |
RPOPLPUSH source destination |
RPUSH | 1. 将一个或多个值 value 插入到列表 key 的表尾 | RPUSH key value [value …] |
RPUSHX | 1. 将 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表 2.key 不存在,RPUSHX 什么都不做 |
RPUSHX key value |
实际 :别偷懒,入手一下,try it out
三、利用场景
1、lpush+lpop=Stack(栈)
2、lpush+rpop=Queue(队列)
3、lpush+ltrim=Capped Collection(无限汇合)
4、lpush+brpop=Message Queue(音讯队列
)
5、排行榜,数据最新列表等等
四、底层解析
结构图上显示,List 类型有两种实现形式:
举例说明,创立列表对象 numbers
1、应用压缩列表(ziplist)实现的列表对象
构造如下
2、应用双端链表(linkedlist)实现的列表对象
构造如下
五、疑难思考
压缩列表与双端链表是什么样的构造?
1、压缩列表(ziplist)
压缩列表(ziplist)是 Redis 为了节俭内存而开发的,是由一系列非凡编码的间断内存块组成的程序型数据结构,一个压缩列表能够蕴含任意多个节点(entry),每个节点能够保留一个字节数组或者一个整数值。
构造如下
压缩列表的每个节点形成如下
1)previous_entry_ength:以字节为单位,记录了压缩列表中前一个字节的长度。previous_entry_ength 的长度能够是 1 字节或者 5 字节:
如果前一节点的长度小于 254 字节,那么 previous_entry_ength 属性的长度为 1 字节,前一节点的长度就保留在这一个字节外面。
如果前一个节点的长度大于等于 254,那么 previous_entry_ength 属性的长度为 5 字节,其中属性的第一字节会被设置为 0xFE(十进制 254),而之后的四个字节则用于保留前一节点的长度。
利用此原理即以后节点地位减去上一个节点的长度即失去上一个节点的起始地位,压缩列表能够从尾部向头部遍历,这么做很无效地缩小了内存的节约。
2)encoding:记录了节点的 content 属性所保留数据的类型以及长度。
3)content:保留节点的值,节点的值能够是一个字节数组或者整数,值的类型和长度由节点的 encoding 属性决定。
2、双端链表(linkedlist)
链表是一种罕用的数据结构,C 语言外部是没有内置这种数据结构的实现,所以 Redis 本人构建了链表的实现。
链表节点定义:
typedef struct listNode{
// 前置节点
struct listNode *prev;
// 后置节点
struct listNode *next;
// 节点的值
void *value;
}listNode
多个 listNode 能够通过 prev 和 next 指针组成双端链表,构造如下
另外 Redis 还提供了操作链表的数据结构:
typedef struct list{
// 表头节点
listNode *head;
// 表尾节点
listNode *tail;
// 链表所蕴含的节点数量
unsigned long len;
// 节点值复制函数
void (*free) (void *ptr);
// 节点值开释函数
void (*free) (void *ptr);
// 节点值比照函数
int (*match) (void *ptr,void *key);
}list;
list 构造为链表提供了表头指针 head,表尾指针 tail 以及链表长度计数器 len,dup、free、match 成员则是用于实现多态链表所需的类型特定函数。
Redis 链表实现的个性 :
- 双端:链表节点带有 prev 和 next 指针,获取某个节点的前置节点和后置节点复杂度都是 O(1)。
- 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的拜访以 NULL 为起点。
- 带表头指针和表尾指针:通过 list 构造的 head 和 tail 指针,程序获取链表的表头节点和表尾结点的复杂度都是 O(1)。
- 带链表长度计数器:程序应用 list 构造的 len 属性对 list 持有的链表节点进行计数,程序获取链表中节点数量的复杂度为 O(1)。
- 多态:链表节点应用 void* 指针来保留节点值,并且通过 list 构造的 dup、free、match 三个属性为节点值设置类型特定函数,所以链表能够用于保留各种不同类型的值。
疑难 :Redis 列表什么时候会应用 ziplist
编码,什么时候又会应用 linkedlist
编码呢?下节再说 …