[Redis] Redis中的Hash类型和List类型
🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
目录
- 1. Redis中关于Hash相关的操作
- 1.1 Hash的存储方式
- 1.2 关于Hash的常见命令
- 1.3 指令小结
- 2. Hash的内部编码方式
- 3. hash的应用场景
- 3.1 作为缓存
- 4. Redis中关于List的操作
- 4.1 概述
- 4.2 特点
- 4.3 相关指令
- 4.4 阻塞版本指令
- 4.4.1 特点概述
- 4.4.2 指令
- 4.5 指令小结
- 5. list内部编码方式
- 6. list的应用场景
1. Redis中关于Hash相关的操作
1.1 Hash的存储方式
在我们之前学习数据结构的时候,我们就曾经接触过HashMap等哈希表相关的集合类.我们知道,在哈希表中存储的是键值对的结构.这里Redis中存储数据本身就是以键值对的形式存储的. 其中key是string类型的数据,要是想要在Redis中存储Hash,那么Redis中的value的类型就是Hash类型的数据.也就是在Hash中又存储了一层Hash.
注意事项: 为了区分Redis中整体的键值对和Hash数据类型的键值对,我们一般把Hash的键值对分别叫做key-field,Redis整体的键值对叫做key-value.
1.2 关于Hash的常见命令
Hash相关操作的命令一般在前面都有一个h开头.
- hset
hset key field value [field value...]
设置Hash中的指定字段和指定值,可以一次性设置多个,也可以一次性设置一个.返回添加字段的个数. - hget
hget key field
获取某Hash中field的value.一次只可以获取一个.
127.0.0.1:6379> hset key1 field1 value1 field2 value2
(integer) 2
127.0.0.1:6379> hget key1 field1
"value1"
127.0.0.1:6379> hget key1 field2
"value2"
- hexists
hexists key field
判断某个Hash中的某个field是否存在.
127.0.0.1:6379> HEXISTS key1 field1 field2
(error) ERR wrong number of arguments for 'hexists' command
127.0.0.1:6379> HEXISTS key1 field1
(integer) 1
注意: 在hexists命令中,不支持一次性查询多个field,一次只可以查询 一个field.
- hdel
hdel key field [field]
删除Hash中的元素,可以一次删除一个元素,也可以一次删除多个元素.返回的是本次操作成功删除的字段.
127.0.0.1:6379> hdel key1 field1
(integer) 1
127.0.0.1:6379> hget key1 field1
(nil)
- hkeys
hkeys key
查询指定key中的所有字段.
127.0.0.1:6379> hkeys key1
1) "field2"
- hvals
hvals key
查询指定key中的所有值.
127.0.0.1:6379> hvals key1
1) "value2"
- hgetall
hgetall key
获取指定key中的所有的field和value.返回值是Hash中所有的键值对.
127.0.0.1:6379> hgetall key1
1) "field2"
2) "value2"
[注意事项] 以上的三个操作和前面我们提到的string的
keys *
一样,存在一定的风险,我们不可以确定这个key对应的Hash中是否有很多键值对.
redis中倒是有这么一个命令会避免这些风险,它叫hscan
,它属于渐进式遍历的指令,就是敲一次命令,遍历一小部分,再敲一次,在遍历一部分.有点像我们在多线程中学习的ConcurrentHashMap
的扩容机制,扩容复制元素的时候并不是一次性全部把元素全部拷贝过去,新老数组同时存在,之后每对ConcurrentHashMap
操作一次,就拷贝一部分,直到把老数组的元素全部拷贝完成,老数组就会被删除.
- hmget
hmget key field [field...]
一次性查询Hash中多个字段的值,返回查询到的value.
127.0.0.1:6379> hset key2 field1 value1 field2 value2 field3 value3
(integer) 3
127.0.0.1:6379> hgetall key2
1) "field1"
2) "value1"
3) "field2"
4) "value2"
5) "field3"
6) "value3"
127.0.0.1:6379> hmget key2 field1 field2 field3
1) "value1"
2) "value2"
3) "value3"
有的人现在就会想到,有没有hmset
,用来一次性设置多个Hash中的键值对呢?有,但是没有必要,因为我们之前讲到的hset
指令就可以一次性设置多个键值对.
- hlen
hlen key
获取Hash中的元素个数.
127.0.0.1:6379> hmget key2 field1 field2 field3
1) "value1"
2) "value2"
3) "value3"
127.0.0.1:6379> hlen key2
(integer) 3
- hsetnx
hsetnx key field value
类似与string操作中的setnx,如果Hash中不存在对应的键值对的话,才可以创建成功,如果存在,就创建失败.
127.0.0.1:6379> hsetnx key2 field4 value4
(integer) 1
127.0.0.1:6379> hgetall key2
1) "field1"
2) "value1"
3) "field2"
4) "value2"
5) "field3"
6) "value3"
7) "field4"
8) "value4"
127.0.0.1:6379> hsetnx key2 field2 value2
(integer) 0
- hincrby
hincrby key field increment
给指定的Hash中的字段对应的值加上指定的值.返回的值是加上指定值之后的值.
127.0.0.1:6379> hset key2 field5 1
(integer) 1
127.0.0.1:6379> HINCRBY key2 field5 2
(integer) 3
127.0.0.1:6379> hget key2 field5
"3"
- hincrbyfloat
hincrbyfloat key field incrment
给指定的Hash中的字段对应的值加上指定的小数.返回加上指定值之后的值.
127.0.0.1:6379> HINCRBYFLOAT key2 field5 0.7
"3.7"
127.0.0.1:6379> hget key2 field5
"3.7"
[注意] 在Redis中并没有对Hash提供像string那样的incr,decr,decrby类似的命令,我们想要对Hash对应字段的值+1,只可以使用
hincrby key field 1
这样的命令,想要-1,就需要hincrby key field -1
这样的指令来代替,想要减指定的值,比如-2,就只能使用hincrby key field -2
这样的指令来代替.其他的一些操作与上同理.
127.0.0.1:6379> hget key2 field5
"3.7"
127.0.0.1:6379> hincrbyfloat key2 field5 -0.2
"3.5"
127.0.0.1:6379> hset key2 field6 8
(integer) 1
127.0.0.1:6379> HINCRBY key2 field6 -2
(integer) 6
1.3 指令小结
2. Hash的内部编码方式
Hash内部编码的方式有两种,一种是hashtable
,一种是ziplist
.
- ziplist
在Hash内部元素比较少(默认阈值512个)而且字段对应的值字节数都比较短(默认阈值64字节)的时候,我们一般使用ziplist
.
ziplist会对Hash表进行一定的压缩,会占用比较少的空间.但是也有一定的代价.就是在读写元素的时候,速度是比较慢的,如果元素个数较少,慢一点也不明显,但是如果元素比较多,读写慢就会让Hash雪上加霜. - hashtable
在hash中的元素个数比较多,或者是某一个元素对应的值的字节数比较长,就会让hash的编码方式从原来的ziplist转变为hashtable.
*其中转变阈值可以在Redis(/etc/redis/redis.conf)的配置文件中设置.*一个属性是hash-max-ziplist-entries,用于配置限制hash中元素的个数,一个属性是hash-max-ziplist-value,用于配置hash中每个value中的长度限制.
下面对编码方式的转换进行验证:
127.0.0.1:6379> hset key3 field1 value1 field2 value2
(integer) 2
127.0.0.1:6379> OBJECT encoding key3
"ziplist"
127.0.0.1:6379> hset key3 field3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
(integer) 1
127.0.0.1:6379> OBJECT encoding key3
"hashtable"
127.0.0.1:6379> hmset hashkey f1 v1 h2 v2 f3 v3 ... 省略 ... f513 v513
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"
3. hash的应用场景
3.1 作为缓存
Redis中存储用户信息的方式不同于MySQL数据库,Redis是一种非关系型数据库,MySQL是一种关系型数据库,Redis中存储数据是以键值对的方式(映射关系)存储的,MySQL中存储数据是以表的方式存储的.
比如我们想要在Redis和MySQL中存储用户信息.
关系型数据表存储结构如下:
映射关系存储结构如下:
- 从上述的数据存储的方式中,我们可以看出,使用hash的方式存储数据在读写的时候更加的直观高效.
- 哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的field,而关系型数据库⼀旦添加新的列,所有行都要为其设置值,即使为null.
- 但是Redis也相对于MySQL有一定的缺点,Redis付出一些空间的代价.这是因为hash在编码转换的时候,需要消耗一定的内存空间.其次,关系数据库可以做复杂的关系查询,而Redis去模拟关系型复杂查询,例如联表查询、聚合查询等基本不可能,维护成本高.
上述这种数据的存储使用json字符串的方式也可以存储.
如果我们使用json字符串的话,只读取某一个字段的时候,需要先把json读取出来,之后解析为对象,之后对想要操作的指端进行操作,之后再重写为json字符串,之后再重新写回去.
如果使用hash的凡是来表示的时候,就可以直接使用字段中相应的值,此时就可以非常方便的修改和获取一个属性的值了.避免了对象和字符串之间来回解析的工作.
我们还可以使用原生字符串的形式表示,*使用Redis中的字符串类型,每个属性一个键值对.
set user:1:name James set user:1:age 23 set user:1:city Beijing
这种表示方式,相当于把同一个数据给分散开表示了,这样的表现方式就是低内聚的表现方式.而使用hash来存储数据,就会把同一个对象的所有数据都保存在一起.这样的表现方式就是高内聚的.我们在编程的时候,一般使用的是高内聚的表现方式.
4. Redis中关于List的操作
4.1 概述
提到list我们会想到java中的List集合,这样的List就相当于数组或者是顺序表.
但是Redis中的List并非是一个简单的数组,更接近于双端队列(deque).因为Redis中的list支持头插,头删,尾插,尾删,还可以获取指定范围之内的元素和指定下表的元素(和python一样,支持负数下标).它可以充当栈和队列的角色.在实际开发中的应用场景非常广泛.
4.2 特点
- 列表中的元素是有序的
这里的有序,指的是list中的元素可以通过下标来访问.这里的下标可以是正数下表,可以是负数下标.和python一样,正数下标从0开始,负数下标从-1开始.正数表示的是第n+1个元素,负数表示的是倒数第n个元素. - 区分删除和获取的区别
这里之所以要区分,是因为删除和获取的返回值都是指定下标的值.容易混淆. - 列表中的元素允许重复
-
4.3 相关指令
- lpush
lpush key element [element...]
从list的左端插入指定的元素,(lpush中的l就是left的缩写). 可以一次插入多个元素,也可以一次插入一个元素.这里需要注意的是,并不是把这些所有的元素整体进行头插,而是按照顺序依次头插.比如我们要在一个list中插入1234,插入完成之后,list的头部是4321的顺序.如果key不存在,创建列表,如果已经创建了key,key对应的value必须是列表类型,否则报错. - lrange
lrange key start stop
查询列表中指定范围的所有元素.这个指令支持负数下标.其中start区间和stop区间都是闭区间.(这里的l和上面的l意义不一样,这里的l指的是list),如果想要查询list中所有元素的值,就需要使用lrange key 0 -1
这个指令.
127.0.0.1:6379> lpush key1 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange key1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
谈到下标,我们往往就会关注下标越界的情况,在java中,要是数组或者线性表下表越界,就会抛出下表越界的异常.但是Redis中并没有采取上述的方案.Redis中的做法,==是直接尽可能的获取到给定区间的元素.==如果给定区间不合法,就会尽可能在不合法的区域中获取元素.此处对于下表的处理方式,类似与python中的列表切片.
127.0.0.1:6379> lrange key1 0 100
1) "4"
2) "3"
3) "2"
4) "1"
比如我们给出的范围是0~100,在这个区间内只有4321,那么Redis也只能获取4321这4个元素.
- lpushx
lpushx key element [element...]
在指定的list的左边插入元素,这个指令和lpush最大的区别就是,如果这个key不存在的时候,不会自动创建key,只可以在已经存在的key的list中头插元素.
127.0.0.1:6379> lpushx key1 4 3 2 1
(integer) 8
127.0.0.1:6379> lrange key1 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "4"
6) "3"
7) "2"
8) "1"
127.0.0.1:6379> lpushx key2 4 3 2 1
(integer) 0
127.0.0.1:6379> get key2
(nil)
我们从上面的代码中可以看出,如果key不存在的时候,会返回0,而且不会主动创建key.
- rpush
rpush key element [element...]
在list的右边插入指定的元素(这里的r就是right的缩写),可以一次插入多个元素,也可以一次插入一个元素.如果key不存在,创建列表,如果已经创建了key,key对应的value必须是列表类型,否则报错.
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> lrange key 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
- rpushx
在指定的list的右边插入元素,这个指令和rpush最大的区别就是,如果这个key不存在的时候,不会自动创建key,只可以在已经存在的key的list中头插元素.
127.0.0.1:6379> rpushx key3 1 2 3 4
(integer) 0
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> rpushx key 1 2 3 4
(integer) 8
127.0.0.1:6379> lrange key 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "1"
6) "2"
7) "3"
8) "4"
- lpop
lpop key
从list的最左边取出元素,即头删.
127.0.0.1:6379> lpop key
"1"
127.0.0.1:6379> lpop key
"2"
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "4"
3) "1"
4) "2"
5) "3"
6) "4"
- rpop
从list的右边取出元素,即尾删
127.0.0.1:6379> rpop key
"4"
127.0.0.1:6379> rpop key
"3"
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "4"
3) "1"
4) "2"
在Redis5的版本中,没有设置count参数,即一次可以pop元素的个数,但是从6.2开始,新增了一个count参数,可以指定pop元素的个数.比如
rpop key [count]
.
Redis中的list相当于一个双端队列,从两头插入/删除元素都非常高效,搭配使用rpush和lpop就相当于队列,搭配使用rpush和rpop就相当于栈.
- lindex
lindex key index
获取指定位置的元素.如果下标是非法的,返回的就是nil
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "4"
3) "1"
4) "2"
127.0.0.1:6379> lindex key 2
"1"
127.0.0.1:6379> lindex key 100
(nil)
- linsert
linsert key <before|after> pivot element
在list中指定元素的位置插入指定的元素.可以在指定元素的左边插入,也可以在指定元素的右边插入.在查找list中指定元素的时候,如果在list中找到了多个基准值,值插入第一个.返回值是插入之后得到的心得list长度.
127.0.0.1:6379> rpush key 4 4
(integer) 6
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "4"
3) "1"
4) "2"
5) "4"
6) "4"
127.0.0.1:6379> linsert key before 4 22
(integer) 7
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "4"
4) "1"
5) "2"
6) "4"
7) "4"
127.0.0.1:6379> linsert key after 4 22
(integer) 8
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "4"
4) "22"
5) "1"
6) "2"
7) "4"
8) "4"
- llen
llen key
获取list的长度
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "4"
4) "22"
5) "1"
6) "2"
7) "4"
8) "4"
127.0.0.1:6379> llen key
(integer) 8
- lrem
lrem key count element
删除list中指定的值,其中count是要删除的个数,element是要删除的元素.
其中,count > 0的时候,从list的左边开始删除指定个数的元素,count = 0的时候,将指定的元素全部删除.当count < 0的时候,从list的右边开始删除指定个数的元素.
127.0.0.1:6379> lrem key 1 4
(integer) 1
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "22"
4) "1"
5) "2"
6) "4"
7) "4"
127.0.0.1:6379> lrem key -2 4
(integer) 2
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "22"
4) "1"
5) "2"
127.0.0.1:6379> lpush key 4 4 4
(integer) 8
127.0.0.1:6379> lrem key 0 4
(integer) 3
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "22"
4) "1"
5) "2"
- ltrim
itrim key start stop
保留指定区间(闭区间)之内的元素,其他元素全部删除.
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "22"
3) "22"
4) "1"
5) "2"
127.0.0.1:6379> ltrim key 1 3
OK
127.0.0.1:6379> lrange key 0 -1
1) "22"
2) "22"
3) "1"
- lset
lset key index element
将指定下标的元素修改为指定元素.
注意: 这里不像lrange那样下标可以越界,这里的下标如果越界了,会报错.
127.0.0.1:6379> lrange key 0 -1
1) "22"
2) "22"
3) "1"
127.0.0.1:6379> lset key 1 44
OK
127.0.0.1:6379> lset key 5 55
(error) ERR index out of range
127.0.0.1:6379> lrange key 0 -1
1) "22"
2) "44"
3) "1"
4.4 阻塞版本指令
4.4.1 特点概述
- 阻塞指的就是: 当前线程的代码不会继续执行,会在满足一定条件之后唤醒.但是只有当前客户端表现为阻塞状态,不会影响到其他客户端的Redis指令的执行.
- 如果list中存在元素,blpop,brpop的效果和不加b(这里的b就是block的缩写)完全一样.如果list不存在元素,blpop,brpop就会阻塞等待,一直阻塞到list不为空或者是超时为止.
说到这里,我们可以回忆一下我们java中的BlockingQueue.java中的阻塞队列主要用于生产者消费者模型.它一方面主要用于生产者和消费者的削峰填谷,另一方面用于解除生产者和消费者的强耦合.
- Redis这里的list与阻塞相关的指令也是一样.只是这里的线程安全是通过单线程来实现的,阻塞只支持"队列为空"的情况,不支持"队列为满"的情况,和阻塞相关的指令只有pop相关的操作.
- 这里的阻塞等待也不是无休止的阻塞等待,我们可以自定义阻塞等待的时间.
- 命令中如果设置了多个键,会从头到尾遍历所有的键,一旦有个一键对应的列表中可以弹出元素,命令立即返回.也就是blpop和brpop都可以同时尝试获取多个key的列表元素,多个key对应多个list,哪个list中有元素,就返回哪个元素.
- 如果有多个客户端同时对一个键执行pop,则最先执行命令的客户端会得到弹出的元素.
4.4.2 指令
- blpop
blpop key [key...] timeout
指定要弹出元素的list对应的key,这个key可以有多个,可以只有一个,命令中如果设置了多个键,会从头到尾遍历所有的键,一旦有个一键对应的列表中可以弹出元素,命令立即返回.可以指定阻塞等待的时间,如果在等待时间之内list中新增了元素,则立即返回.如果超时,则返回nil.如果获取到元素,返回的值是一个二元组,分别是得到返回值的key(也就是告诉我们当前数据来自于哪个key)和list中弹出的值(数据是什么).
127.0.0.1:6379> lpush key2 100
(integer) 1
127.0.0.1:6379> blpop key2 5
1) "key2"
2) "100"//有元素立即弹出,无需等待
127.0.0.1:6379> lpush key3 100
(integer) 1
127.0.0.1:6379> lpush key4 100
(integer) 1
127.0.0.1:6379> blpop key2 key3 key4 5
1) "key3"//弹出第一个获取到元素的key中的元素
2) "100"
127.0.0.1:6379> blpop key3 5
(nil)
(5.04s)//如果指定的key中没有元素,阻塞等待,最后返回nil
//客户端1
127.0.0.1:6379> blpop key3 100
1) "key3"
2) "1"
(33.40s)
//客户端2
127.0.0.1:6379> lpush key3 1
(integer) 1//在一个客户端阻塞的期间,不影响其他客户端的命令执行
//在等待期间,在客户端2中对key3插入元素,只要key3中有了元素,客户端1中阻塞等待的命令就会立即返回
- brpop
和blpop是同样的道理,只不过是尾删.
4.5 指令小结
5. list内部编码方式
在旧版本的Redis中,Redis中的编码方式分为了两种,一种是ziplist,一种是linkedlist.
- ziplist
这个ziplist的编码方式和hash中的ziplist的编码方式的限制条件是一样的,在list中的元素较少的时候(默认512个),或者是list中每个元素很短(默认不超过64字节).按照这种编码方式可以节省一定的空间,但是缺点就是读取的时候是比较慢的. - linkedlist
在list内部的元素个数和每个元素的字节长度超过阈值的时候,就会转换为linkedlist.
但是在新版本中的Redis中,list的编码方式并不是采用这样的方式,它采用的是quicklist的方式.
关于quicklist,它相当于结合了ziplist和linkedlist两者的优点.整体还是一个链表,但是每个链表的结点是一个压缩链表.每个压缩列表都不是很大,这些研所列表是通过链式结构连接起来的.
在之前配置文件中的list-max-ziplist-entries和list-max-ziplist-value这两个属性由于list底层编码方式的改变,现在都不再使用了.
6. list的应用场景
- 用list作为想数组这样的结构来存储数据
假如我们有这样两种数据,一种是班级,一种是学生.
在Redis中,我们存储学生信息的时候使用的是hash的方式来存储的,中存储的是学生的id,value中的hash中存储的是学生的各种不同的信息.存储班级信息的时候,key中存储的是class的id,value中存储的是该班级中有多少人.但是我们想要存储class中有哪些学生,我们就需要list存储,在key中存储的是class的id,在value中使用list存储的是学生的id.
由于Redis只能存储键值对,并不像MySQL中使用表存储数据,并提供了丰富的查询功能,所以在Redis中如何组织数据,就要根据实际的业务场景来决定.
- 用作消息队列
list中的阻塞命令可以为Redis作为消息队列提供很好的支持.和java一样,Redis作为消息队列的时候,一般也是用于生产者消费者模型.
这里我们假如生产者只有一个,那么生产者就会把信息交给Redis中的列表,其中列表就是消息队列,消费者有好多个.==这里消费者在获取信息的时候,是通过轮训的方式来获取信息.==谁先执行的drpop,谁就可以先获取到信息,此消费者获取完信息之后,假如还想要使用brpop获取信息,就会到达消费者优先级的末尾.比如消费者执行的顺序是123,在1消费者执行完成之后,1消费者想要再次获取消息队列中的元素,这时候就要排到消费者优先级的末尾,也就是按照231的方式执行的.消费者2也是同样的道理.
具体说明: 买包子
假如滑稽老铁有一天想吃包子,他要去包子摊买包子,轮到他的时候,他买了2个包子,刚一出队列,一想到自己还没有给女票带早饭,又想返回头去再买一个包子,这时候滑稽老铁一定是不可以插回原来的位置的,他只能到队尾再次进行排队.
- 分频道的消息队列
我们在Redis中,可能不止一个列表在作为消息队列,可能有多个消息队列,不同的消息队列中保存的是不同主题的消息.一个消费者可以从多个频道中获取信息.每一个消息队列都和上面我们提到的消息队列的特点是一样的.这样搞成多个频道的消息队列,可以在某种主题的数据发生问题的时候,不会对其他的频道造成影响.