redis-list的基本介绍
这里的list指的是redis存的键值对中的值,也就是value,数据类型是list,也就是列表,也可以说是数组,数组中存的元素就是字符串,也可以是很多个字符串,也可以是一个字符串;接下来大概画个图表示一下在redis中,是如何使用list存放数据的;
首先,不用质疑,key就是键值对的键,是redis中是唯一的,而value是一个列表,用来存放不同的数据,但是list的中的每一个元素不会具有唯一性,可以是相同的,列表中的元素的下标:从左往右一次就是0,1......,也可以用负数来表示,那从右往左就是-1,-2,-3 ....,下表的关系:正数的下标-列表的长度==负数的下标;从上面的图也可以看出,lpush就是可以从左边插入元素,也就是从对头插入元素,rpush就是可以从右边插入元素,也就是队尾插入元素,lpop就是可以出队头的元素,rpop就是可以出队尾的元素,从list可以支持对头和队尾插入和出元素就可以看出来,list类似于一个队列,而且是双端队列,也可以让我联想到消息队列,或者生产者消费者模型,而且redis最早做list也是本来就打算用来做消息队列的,但是后面发现这一个功能相对于市面上专门的消息队列,比如mq,kafka等来说就显得不是那么完美了,但是redis也保留了list可以作为消息队列这一个功能。
接下来介绍一下value为list的一些具体用法。
1、lpush key element [element .....]
这个指令就是从对头依次插入每一个元素到列表中,比如lpush key 1 2 3,那么列表中的元素顺序就是【3 2 1】 ,时间复杂度就是O(N),N是插入的元素的个数,一次性插入几个元素就可以节约网络带宽,返回值是插入之后list的总长度;值得注意的是如果key的value类型不是list就会保存,这在redis是通用的,list的操作指令操作对象就必须是list,如果是别的类型就肯定会报错;如果key不存在,就会去创建一个新的,并插入要插入的元素;
2、lrange key start end
这个指令是去返回list的一个区间的所有元素,区间就是[start end],包含start和end;但是值得注意的这个start和end可以是负数,也可以是正数,而且redis会尽可能的返回正确的一个区间的所有元素,比如是【0 -1】就是返回所有的的元素,如果是[0,100]的话要看你的list的长度是多少,如果长度>101 ,那就是返回前101个元素,如果长度小于101,比如只有10个,那么redis不会报错,而是返回全部的这个10个元素,因为redis认为你并没有101个元素,只有10个元素,那么我就给你返回,这就是说为什么redis会尽快的返回一个正确的;
这就涉及到一个下标越界的问题,如果是在C++的话,下标越界问题,会是一个“未定义行为”,什么是未定义行文,就是C++可能会返回一个并且合理的结果,但是不一定是争取的,也有可能会返回一个报错,更有可能返回一个错误的结果的,返回的结果不是一个明确的,就是说如果你的下标越界,我就返回一个结果,因为C++返回的结果有很多种可能,所以说是未定位行为;相比较Java就不一样了,Java对于下标越界就进行了非常严格的校验,直接给你抛出一个异常;其实这两种方法都有好处和坏处,C++的好处就是快,少了一步校验参数,肯定就快了,但是确定也很明显,虽然下标越界有时候能跑,但是始终是一个安全隐患,说不定指不定那一天就爆出了一个大雷;而Java就对下标进行校验,如果越界我就给你报错,有好处也有坏处,坏处就是慢了一点,多一个校验和抛出错误,一但没有处理好抛出的异常,那程序可能一下子就崩溃了;好处也有,这就能够提醒程序员,要去对下标,对抛出的异常进行好好的处理;
但是redis其实这种方法都没有使用,而是使用了一种更为简单粗暴的方式,尽量的返回合法数据,比如上面的例子,其实这也类似于Python的切片,这样有一个特点就是鲁棒性;
3、lpushx
这个指令相比较lpush多了一个x,有两种情况,如果key是存在,这个指令的效果就相当于lpush,从list的左边依次插入元素;如果key不存在,那就直接返回,不进行任何的插入元素的操作;
4、rpush key element[element element ....]
这个指令是在key的后面依次去插入多个元素,比如rpush key 4 5 6,原来list中有元素顺序为1 2 3,那么插入后的list内容顺序就是1 2 3 4 5 6,效果相当于是在后面拼接上多个元素,特点其实和lpush差不多,都是时间复杂度O(N),一次性多插入几个就可以网络带宽,返回值都是插入后的list的长度,而且如何key不存在,就会去创建一个新的键值对;如果key存在且value为list,就会往list的后面插入元素,如果value不是list就会报错;
5、rpushx
这两个指令其实和lpop,lpushx是一致的,这里不错多的赘述;
6、lpop | rpop key
lpop和rpop都是删除元素并且返回,如果没有元素可以删除,就返回nil;lpop是在队头元素,rpop是在队尾出元素;值得一提的是在redis6.2开始就支持一次性出多个元素,rpop key [count],count指的就是出多个元素,而且此处redis还是会尽可能出够count个元素,如果不够,也会出list的全部元素,并不会说报错;
7、lindex key index
这个指令是去获取并返回list中下标为index的元素,下标可以是负数,就像我们上面图中画的一致;如果index非法,也及时下标所指的元素不存在,就会返回nil;
8、linsert key [before | after] pivot element
从这个指令的字面意思就可以看出来,这是在往list中插入元素,而且可以选择某个元素的前面或者后面去插入元素值element,pivot指的是value的值,并不是下标,redis会在list从左往右找到第一个值为pivot的,然后在这个指的前后或者后面插入一个element;为什么说是遇到到第一个,是因为一个list的值是可以一致的,也就是一个list可能会出现多个值相同的value,所以说是从左往右第一个;返回值为list的新长度;
9、lrem key count element
这里根据count的值去key中删除若干个值为elemnet的元素,为什么说是若干个呢?如果count>0,那么就是去key中从左往右删除count个element;如果count<0,那就是从右往左删除count的绝对值个element;如果count==0,并不是不删除,而是删除所有值等于element的元素;时间复杂度及时O(n);
10、ltrim key start end
去获取key对应的值list中存的元素,而且是下标是start和end的闭区间的全部元素,比如list中存的0 1 2 3 4 5 6;指令ltrim key 2 4,返回的就是2 3 4,
11、lset key index element
这个指令是去将index下标的元素设置为element,时间复杂度是O(N),N指的是从开头去到这个下标的步数,不是一整个list的长度,如果下标非法就会报错;
12、blpop,brpop key [key ...] timeout
这两个指令实际是上rpop,lpop是一样的都是从对头或者队尾去出元素,唯一不同的的是多了一个b,这个b有阻塞的作用,发挥作用的时候就去当监听的key中list长度为0的时候,这个时候回去阻塞等待时间,还可以指定等待时间timeout,单位是秒;还可以一次性监听多个key,只要有一个key有元素,那么这个指令就立刻返回一个pairs,就是返回一个键值对;
以上所有的指令都不用刻意去记住,只要多多练习,就能够记住了;