目录
- 0.前言
- 1.常用命令
- 1.LPUSH / RPUSH
- 2.LPUSHX / RPUSHX
- 3.LRANGE
- 4.LPOP / RPOP
- 5.LINDEX
- 6.LINSERT
- 7.LLEN
- 8.LREM
- 9.LTRIM
- 10.LSET
 
- 2.阻塞版本命令
- 0.是什么?
- 1.BLPOP / BRPOP
 
- 3.内部编码(旧版本,仅供参考)
- 1.ziplist(压缩链表)
- 2.linkedlist(链表)
- 3.quicklist(快速链表) -> (现行方案)
 
- 4.使用场景
- 1.消息队列
- 2.分频道的消息队列
- 3.微博 Timeline
 
0.前言
-  列表类型是⽤来存储多个有序的字符串,相当于数组/顺序表 - 内部实现类似于”双端队列“(deque)
 
-  列表中的每个字符串称为元素(element),⼀个列表最多可以存储 2 32 − 1 2^{32} - 1 232−1个元素 
-  在Redis中,可以对列表两端插⼊( push)和弹出(pop),还可以获取指定范围的元素列表、 获取指定索引下标的元素等
   
-  列表是⼀种⽐较灵活的数据结构,它可以充当栈和队列的⻆⾊,在实际开发上有很多应⽤场景 
-  列表类型的特点: - 列表中的元素是有序的:这意味着可以通过索引下标获取某个元素或者某个范围的元素列表
- 区分获取和删除的区别:rem是删除,会导致列表的长度改变,index是获取元素,列表长度不会变化
- 列表中的元素是允许重复的,而hash这样的类型,field是不能重复的
  
 
1.常用命令
1.LPUSH / RPUSH
- 功能:将一个或者多个元素从左侧(头插) / 右侧(尾插)放入到list中- 注意:是按照键入在命令中的顺序,从左向右将命令中的元素插入到list中的- 例如:LPUSH key 1 2 3 4,那么最后list呈现的结果为:4 3 2 1
 
- 例如:
 
- 注意:是按照键入在命令中的顺序,从左向右将命令中的元素插入到
- 语法:LPUSH/RPUSH key element [element ...]
- 返回值:插入后list的长度
- 时间复杂度:只插入一个元素为 O ( 1 ) O(1) O(1),插入多个元素为 O ( N ) O(N) O(N),N为插入元素个数
2.LPUSHX / RPUSHX
- 功能:在key存在时,将⼀个或者多个元素从左侧(头插) / 右侧(尾插)放⼊到list中,不存在,直接返回
- 语法:LPUSHX/RPUSHX key element [element ...]
- 返回值:插入后list的长度
- 时间复杂度:只插入一个元素为 O ( 1 ) O(1) O(1),插入多个元素为 O ( N ) O(N) O(N),N为插入元素个数
3.LRANGE
- 功能:获取从start到end区间的所有元素,左闭右闭,下标支持负数
- 语法:LRANGE key start stop
- 返回值:指定区间的元素
- 时间复杂度: O ( N ) O(N) O(N)
- 注意:Redis会尽可能地获取到给定区间的元素,如果给定区间非法,比如超出下标,就会尽可能地获取到对应的内容 
  - Redis对于下标越界地处理方式类似于Python的切片操作
 
4.LPOP / RPOP
- 功能:从list左侧取出元素(头删) / 右侧取出元素(尾删)
- 语法:LPOP/RPOP key
- 返回值:取出的元素或者nil
- 时间复杂度: O ( 1 ) O(1) O(1)
5.LINDEX
- 功能:获取从左数第index位置的元素
- 语法:LINDEX key index
- 返回值:取出的元素或者nil
- 时间复杂度: O ( N ) O(N) O(N)
6.LINSERT
- 功能:在特定位置插入元素
- 语法:LINSERT key <BEFORE | AFTER> pivot element
- 返回值:插入后的list长度
- 时间复杂度: O ( N ) O(N) O(N),N表示列表的长度
- 注意:LINSERT进行插入的时候,要根据基准值,找到对应的位置,从左往右找,找到第一个符合基准值的位置即可
7.LLEN
- 功能:获取list长度
- 语法:LLEN key
- 返回值:list的长度
- 时间复杂度: O ( 1 ) O(1) O(1)
8.LREM
- 功能:删除元素
- 语法:LREM key count element- count:要删除的个数- count > 0:从头向尾删
- count < 0:从尾向头删
- count = 0:删除全部元素
 
- element:要删除的值
 
- 返回值:删除元素的个数
- 时间复杂度: 
      
       
        
        
          O 
         
        
          ( 
         
        
          N 
         
        
          + 
         
        
          M 
         
        
          ) 
         
        
       
         O(N + M) 
        
       
     O(N+M),N为list的长度,M为要删除元素的个数
9.LTRIM
- 功能:保留[start, stop区间内的元素,区间外面的元素就直接被删除了
- 语法:LTRIM key start stop
- 时间复杂度: O ( N ) O(N) O(N),N为要删除元素的个数
10.LSET
- 功能:根据下标,修改元素
- 语法:LSET key index element
- 时间复杂度: O ( N ) O(N) O(N)
2.阻塞版本命令
0.是什么?
- blpop和- brpop是- lpop和- rpop的阻塞版本,和对应⾮阻塞版本的作⽤基本⼀致,除了:- 在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的 
    - 但如果列表中没有元素,⾮阻塞版本会立即返回nil
- 但阻塞版本会根据timeout,阻塞⼀段时间,期间Redis可以执⾏其他命令,但要求执 ⾏该命令的客⼾端会表现为阻塞状态
 
- 但如果列表中没有元素,⾮阻塞版本会立即返回
- 命令中如果设置了多个键,那么会从左向右进⾏遍历键,⼀旦有⼀个键对应的列表中可以弹出元素,命令⽴即返回
- 如果多个客⼾端同时对⼀个键执⾏pop,则最先执⾏命令的客⼾端会得到弹出的元素
 
- 在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的 
    
- 阻塞版本的blpop和非阻塞版本lpop的区别:-  列表不为空时: 
  
-  列表为空时,且5秒内没有新元素加入: 
  
-  列表为空时,且5秒内有新元素加入: 
  
 
-  
1.BLPOP / BRPOP
- 功能:LPOP/RPOP的阻塞版本
- 语法:`BLPOP/BRPOP key [key …] timeout
- 返回值:取出的元素或者nil
- 时间复杂度: O ( 1 ) O(1) O(1)
3.内部编码(旧版本,仅供参考)
1.ziplist(压缩链表)
- 当列表的元素个数⼩于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的⻓度都⼩于list-max-ziplist-value配置(默认64字节)时,Redis会选⽤ziplist来作为列表的内部编码实现来减少内存消耗
2.linkedlist(链表)
- 当列表类型⽆法满⾜ziplist的条件时,Redis会使⽤linkedlist作为列表的内部实现
3.quicklist(快速链表) -> (现行方案)
- 相当于是链表和压缩列表的结合:整体还是一个链表,链表的每个节点,是一个压缩列表
- 每个压缩列表,都不让它太大,同时再把多个压缩列表通过链式结构连起来
4.使用场景
1.消息队列
- Redis可以使⽤lpush + brpop命令组合实现经典的阻塞式⽣产者-消费者模型队列, ⽣产者客⼾端使⽤lpush从列表左侧插⼊元素,多个消费者客⼾端使⽤brpop命令阻塞式地从队列中 "争抢"队⾸元素。通过多个客⼾端来保证消费的负载均衡和⾼可⽤性
  
2.分频道的消息队列
- Redis同样使⽤lpush + brpop命令,但**通过不同的键模拟频道的概念,不同的消费者可以通过brpop不同的键值,实现订阅不同频道的理念**
  
3.微博 Timeline
- 每个⽤⼾都有属于⾃⼰的Timeline(微博列表),现需要分⻚展⽰⽂章列表。此时可以考虑使⽤列表,因为列表不但是有序的,同时⽀持按照索引范围获取元素
- 每篇微博使⽤哈希结构存储,例如微博中3个属性:title、timestamp、content:hmset mblog:1 title xx timestamp 1476536196 content xxxxx ... hmset mblog:n title xx timestamp 1476536196 content xxxxx
- 向⽤⼾Timeline添加微博,user::mblogs作为微博的键:lpush user:1:mblogs mblog:1 mblog:3 ... lpush user:k:mblogs mblog:9
- 分⻚获取⽤⼾的Timeline,例如获取⽤⼾1的前10篇微博:keylist = lrange user:1:mblogs 0 9 for key in keylist { hgetall key }
- 此⽅案在实际中可能存在两个问题: 
  - 1+n问题:如果每次分⻚获取的微博个数较多,需要执⾏多次hgetall操作,此时可以考虑使⽤pipeline(流⽔线)模式批量提交命令,或者微博不采⽤哈希类型,⽽是使⽤序列化的字符串类型,使⽤mget获取
- 分裂获取⽂章时,lrange在列表两端表现较好,获取列表中间的元素表现较差,此时可以考虑将列表做拆分
 
- 1+n问题:如果每次分⻚获取的微博个数较多,需要执⾏多次



















