Redis的列表数据类型

[size=medium][color=blue][list]
[*]List 类型概述
[*]List 的命令操作
[*]List 数据类型应用案例
[/list][/color][/size]

[size=medium][color=olive][b]List 类型概述 — List 的基本概念[/b][/color][/size]

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

[size=medium][color=olive][b]List 类型概述 — 底层实现[/b][/color][/size]
Redis列表使用两种数据结构作为底层实现:
1. 双端链表
[img]http://dl2.iteye.com/upload/attachment/0113/6673/8fa64294-84da-3b15-bd4a-b5bb3cee8e37.png[/img]
2. 压缩列表
因为双端链表占用的内存比压缩列表要多,所以当创建新的列表键时,列表会优
先考虑使用压缩列表作为底层实现,并且在有需要的时候,才从压缩列表实现转
换到双端链表实现。
[img]http://dl2.iteye.com/upload/attachment/0113/6675/62fb10dc-644f-3d37-87c5-d0bb278185c6.png[/img]

伪代码:
列表:

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;



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

[size=medium][color=olive][b]List 的常用命令[/b][/color][/size]
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。

[size=medium][color=olive][b]List 数据类型应用案例[/b][/color][/size]
[list]
[*]String 类型存储文章 ID
[*]List 类型存储文章 ID
[*]List 类型存储文章评论
[/list]

[color=blue][b]如何获取文章列表[/b][/color]
读取 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 开始遍历。


[size=medium][color=olive][b]List 类型存储文章 ID[/b][/color][/size]

使用列表类型键 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 命令

说明:案例摘抄自极客学院,感谢大牛的分享。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值