Redis的列表数据类型

  • List 类型概述
  • List 的命令操作
  • List 数据类型应用案例


List 类型概述 — List 的基本概念

List是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等,操作中key理解为链表的名字。Redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push、pop操作从链表的头部或者尾部添加删除元素, push和pop命令的算法时间复杂度都是O(1),这样list既可以作为栈,又可以作为队列。链表的最大长度是232-1。

List 类型概述 — 底层实现
Redis列表使用两种数据结构作为底层实现:
1. 双端链表

2. 压缩列表
因为双端链表占用的内存比压缩列表要多,所以当创建新的列表键时,列表会优
先考虑使用压缩列表作为底层实现,并且在有需要的时候,才从压缩列表实现转
换到双端链表实现。


伪代码:
列表:
typedef struct list {
      listNode *head;                 // 表头指针
      listNode *tail;                     // 表尾指针
      unsigned long len;             // 节点数量
      void *(*dup)(void *ptr) ;   // 复制函数
      void (*free)(void *ptr) ;     // 释放函数
      int (*match)(void *ptr, void *key) ;  // 比对函数
}list;
// listNode是双端链表的节点
Typedef   struct  listNode  {
       struct listNode *prev;  // 前驱节点
       struct listNode *next;  // 后继节点
       void *value;   // 值
} listNode;



List 类型概述 — 使用场景
Redis list应用场景非常多,比如:
  • 微博的关注列表
  • 粉丝列表
  • 博客评论
  • 消息队列
  • 取最新 N  个数据的操作
  • 排行榜应用,取 TOP  N 操作


List 的常用命令
LPUSH
语法:LPUSH  key   value
解释:用来向列表左边增加元素,返回值表示增加元素后列表的长度;LPUSH命令还支持同时增加多个元素。

LRANGE
语法:LRANGE  key   start  end
解释:用来获得列表中的某一片段,返回索引从 Start 到 end 之间的所有元素,索引从0开始。LRANGE 命令也支持负索引,-1表示最右边的元素,-2表示最右边倒数第2个元素。

RPUSH
语法:RPUSH  key   value
解释:用来向列表右边增加元素,返回值表示增加元素后列表的长度;RPUSH命令还支持同时增加多个元素。

LINSERT
语法:LINSERT  key   BEFORE | AFTER  pivot  value
解释:此命令首先会在列表中从左到右查找值为pivot的元素,然后根据第2个参数是BEFORE还是AFTER来决定将Value插入到前面还是后面。返回值是插入后元素的个数。

LPOP/RPOP
语法:LPOP/RPOP   key
解释:LPOP命令可以从列表左边弹出一个元素;RPOP从列表右边弹出一个元素。
LPOP和LPUSH配合,RPOP和RPUSH配合可以把列表当作栈使用;LPUSH和RPOP配合,RPUSH和LPOP配合可以把列表当作队列使用。

LREM
语法:LREM  key   count   value
解释:LREM 命令会删除列表中前 count 个值为value 的元素,返回值是实际删除的元素的个数。
当 count >0时,从左边开始删除;
当 count <0时,从右边开始删除;
当 count =0时,删除所有值为 value 的元素;

LTRIM
语法:LTRIM  key   start   end
解释:LTRIM 命令会删除列表中指定索引范围外的所有元素,返回值即指定索引内的元素。LTRIM 命令常和 LPUSH命令一起使用来限制列表中元素的数量,比如记录日志时我们希望只保留最近的100条记录,则每次添加日志时调用一次 LTRIM 命令即可。

RPOPLPUSH
语法:RPOPLPUSH  src   dest
解释:RPOPLPUSH 命令先从 src 列表的右边弹出一个元素,然后将其加入 dest 列表的左边,并返回这个元素的值。当把列表当作队列时,RPOPLPUSH 可以在多个队列中传递数据。当 src 与dest 相同时,此命令会不断的将队尾的元素移动到队首。

LINDEX
语法:LINDEX  key  index
解释:LINDEX 命令用来返回指定索引的元素,索引从0开始。
LSET
语法:LSET key  index  value
解释:将索引为 index 的元素赋值为 value。

LSET
语法:LSET key  index  value
解释:将索引为 index 的元素赋值为 value。

List 数据类型应用案例
  • String 类型存储文章 ID
  • List 类型存储文章 ID
  • List 类型存储文章评论


如何获取文章列表
读取 post:count 键获得博客文章的最大 ID
根据 ID 进行分页(假设每页10条),第 n 页的文章 ID 范围是“最大的文章ID-(n-1)*10”到“max(最大的文章 ID – n*10+1,1)”
对每个ID使用HMGET命令来获取文章的数据,伪代码如下:
页显示10篇文章
$postsPerPage  = 10
# 获得最后发表的文章 ID
$lastPostID = GET posts:count
# 当前页码范围
$start = $lastPostID – ($currentPage - 1) * $postsPerPage
$end = max( $lastPostID – $currentPage  * $postsPerPage +1,1)
# 遍历文章 ID 获取数据
For $i = $start down to $end
# 获取文章的标题和作者并打印出来
post = HMGET post:$i,title,author
         Print $post[0]
         Print $post[1]

缺点:删除文章时影响页码分布,都需要从最大文章 ID 开始遍历。


List 类型存储文章 ID
使用列表类型键 posts:list 记录文章 ID
LPUSH posts:list  文章ID
LREM    posts:list  1  文章 ID
# 使用 LRANGE 实现分页
$postsPerPage  = 10
$start =  ($currentPage - 1) * $postsPerPage
$end =  $currentPage  * $postsPerPage  - 1
$postsID = LRANGE posts:list,$start,$end
# 获取需要显示文章的 ID 列表
For   each   $id   in   $postsID
          $post = HGETALL post:$id
           print  文章标题:$post.title
# 使用列表类型键post:文章 ID:comments来存储文章的评论
$serializedComment = serialize($author,$email,$time,$content)
LPUSH  post:42:comments,$serializedComment
读取评论时使用 LRANGE 命令

说明:案例摘抄自极客学院,感谢大牛的分享。

猜你喜欢

转载自xiaoyun34286136.iteye.com/blog/2263028