【redis】hash和list常用命令

hash类型

Redis自身已经是键值对结构了。Redis自身的键值对就是通过哈希的方式来组织的。

把key这一层组织完成之后,到了value这一层。value的其中一种类型还可以再是哈希。哈希类型中的映射关系通常称为field-value,用于区分Redis整体的键值对(key-value)。注意这里的 value 是指 field 对应的值,不是键(key)对应的值,请注意 value 在不同上下文的作用。

redis命令官网查询

查询命令:

image-20240416153541597

hset hget hexists hdel

hset hget:

hset:设置hash中指定的字段(field)的值(value)。

语法:HSET key field value [field value …]

时间复杂度:插入一组field为0(1),插入N组field为O(N)

返回值:添加的字段的个数。

hget:获取hash中指定字段的值。

语法:HGET key field

时间复杂度:0(1)

返回值:字段对应的值或者nil。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> hset key f1  111
(integer) 1
127.0.0.1:6379> hset key f2  222 f3 333 f4 444
(integer) 3
127.0.0.1:6379> hget key f1
"111"
127.0.0.1:6379> hget key f2
"222"
127.0.0.1:6379> hget key f100
(nil)
127.0.0.1:6379> hget key2 f1
(nil)

hexists hdel:

hexists:判断hash中是否有指定的字段。

语法:HEXISTS key field

时间复杂度:0(1)

返回值:1表示存在,0表示不存在。

hdel:删除hash中指定的字段。

时间复杂度:删除一个元素为O(1).删除N个元素为O(N).

返回值:本次操作删除的字段个数。

-- hexists 命令
127.0.0.1:6379> hexists key f1
(integer) 1
127.0.0.1:6379> hexists key f2
(integer) 1
127.0.0.1:6379> hexists key f100
(integer) 0
127.0.0.1:6379> hexists key2 f1
(integer) 0
-- hdel命令
127.0.0.1:6379> hdel key f1
(integer) 1
127.0.0.1:6379> hexists key f1
(integer) 0
127.0.0.1:6379> hdel key f2 f3
(integer) 2
127.0.0.1:6379> hget key f4
"444"
127.0.0.1:6379> hget key f3
(nil)
127.0.0.1:6379> hget key f2
(nil)
127.0.0.1:6379> hdel key f1
(integer) 0

注意区分hdel和del.

del是删除整个键值对。hdel只是删除一个键值中值是hash类型的一个键值对。

hkeys hvals

hkeys:获取hash中的所有字段。

语法:HKEYS key

时间复杂度:O(N),N为field的个数.

返回值:字段列表。

hvals:和hkeys相对。能够获取到hash中的所有value

语法:HVALS key

时间复杂度:O(N),N为field的个数.

返回值:所有的值。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> hset key f1 111 f2 222 f3 333 f4 444
(integer) 4
127.0.0.1:6379> hkeys key
1) "f1"
2) "f2"
3) "f3"
4) "f4"
127.0.0.1:6379> hvals key
1) "111"
2) "222"
3) "333"
4) "444"

hgetall hmget

hgetall:获取hash中的所有字段以及对应的值。

语法:HGETALL key

时间复杂度:O(N),N为field的个数.

返回值:字段和对应的值。

hmget:一次获取hash中多个字段的值。

语法:HMGET key field [field …]

时间复杂度:只查询一个元素为0(1),查询多个元素为O(N),N为了查询元素个数。

返回值:字段对应的值或者nil。

127.0.0.1:6379> hgetall key
1) "f1"
2) "111"
3) "f2"
4) "222"
5) "f3"
6) "333"
7) "f4"
8) "444"
127.0.0.1:6379> hmget key f1 f2 f3
1) "111"
2) "222"
3) "333"

有没有hmset,一次设置多个field和value呢?答案是又的,但是,并不需要使用.hset已经支持一次设置多个field和value了。

上述hkeys,hvals,hgetall都是存在一定风险的.hash的元素个数太多,执行的耗时会比较长,从而阻塞redis。可以采用,hscan遍历redis的hash.但是它属于"渐进式遍历"。

hlen hsetnx

hlen

语法:hlen key

获取 hash 的元素个数,不需要遍历的

返回值:hash 的元素个数

hsetnx

语法:hsetnx key field value

类似于setnx.不存在的时候,才能设置成功.如果存在,则失败.

返回值:1 - 成功 0 - 失败

127.0.0.1:6379> hlen key
(integer) 4
127.0.0.1:6379> hgetall key
1) "f1"
2) "111"
3) "f2"
4) "222"
5) "f3"
6) "333"
7) "f4"
8) "444"
-- hsetnx.不存在的时候,才能设置成功.如果存在,则失败.
127.0.0.1:6379> hsetnx key f5 555
(integer) 1
127.0.0.1:6379> hsetnx key f5 666
(integer) 0
127.0.0.1:6379> hget key f5
"555"

hincrby hincrbyfloat

hash 这里的 value,也可以当做数字来处理,hincrby 就可以加减整数。hincrbyfloat 就可以加减小数。使用频率不算很高,redis 没有提供类似于 incr decr。

127.0.0.1:6379> hincrby key f1 10
(integer) 121
127.0.0.1:6379> hincrby key f1 -20
(integer) 101
127.0.0.1:6379> hget key f1
"101"
127.0.0.1:6379> hincrbyfloat key f1 0.5
"101.5"
127.0.0.1:6379> hincrbyfloat key f1 -2.5
"99"

hash编码

  1. 哈希中的元素个数比较少,使用ziplist表示.元素个数比较多,使使用hashtable来表示
  2. 每个value的值长度都比较短,使用ziplist表示.如果某个value的长度太长了,也会转换成hashtable
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> hset key f1 111
(integer) 1
127.0.0.1:6379> object encoding key
"ziplist"
127.0.0.1:6379> hset key f2 222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
(integer) 1
127.0.0.1:6379> object encoding key
"hashtable"

list 列表类型

列表 (List) 相当于 数组 或者 顺序表。

注意,list内部的结果(编码方式)。并非是一个简单的数组。而是更接近于"双端队列"(deque)。

约定最左侧元素下标是0,redis的下标支持负数下标。支持头插头删,尾插尾删

列表中的元素是有序的,"有序"的含义,要根据上下文区分。有的时候,谈到有序,指的是**“升序”,“降序”,有的时候,谈到的有序指的是,顺序很关键**。redis的list类型指的就是后者,如果把元素位置颠倒,顺序调换。此时得到的新的List和之前的List是不等价的。

列表中的元素是允许元素重复的。为当前的 List,头和尾都能高效的插入删除元素,就可以把这个 List 当做一个 栈/队列来使用了。Redis 有一个典型的应用场景,就是作为消息队列最早的时候, 就是通过 List 类型。
类型后来 Redis 又提供了一个stream类型来作为消息列。

lpush 和 lrange

lpush:头插,一次可以插入一个元素,也可以插入多个元素。

语法:LPUSH key element [element …]

时间复杂度O(1)。返回值是list的长度.

注意事项:

如果key已经存在,并且key对应的value类型,不是list,此时Ipush命令就要报错。redis中所有的这些各种数据类型的操作,都是类似的效果。

Irange命令查看list中指定范围的元素.

LRANGE key start stop

此处描述的区间也是闭区间,下标支持负数。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> lpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> lpush key 5 6 7 8
(integer) 8
127.0.0.1:6379> lrange key 0 -1
1) "8"
2) "7"
3) "6"
4) "5"
5) "4"
6) "3"
7) "2"
8) "1"
-- 数组越界的情况:
-- Redis 的做法, 是直接尽可能的获取到给定区间的元素, 
-- 如果给定区间非法,比如超出下标。就会尽可能的获取对应的内容。
127.0.0.1:6379> lrange key  0 100
1) "8"
2) "7"
3) "6"
4) "5"
5) "4"
6) "3"
7) "2"
8) "1"
127.0.0.1:6379> lrange key  10 100
(empty array)

"鲁棒性“(你对我越粗鲁,我就表现的越棒)。程序的容错能力更强。

lpushx

lpushx和lpush的操作基本一致,不同之处在于,lpushx在key存在时,将一个或者多个元素从左侧放入(头插)到list中。不存在,直接返回。

127.0.0.1:6379> lpushx key 9 10 11 12
(integer) 12
127.0.0.1:6379> lrange key 0 -1
 1) "12"
 2) "11"
 3) "10"
 4) "9"
 5) "8"
 6) "7"
 7) "6"
 8) "5"
 9) "4"
10) "3"
11) "2"
12) "1"
127.0.0.1:6379> lpushx key2 1 2 3 4
(integer) 0
127.0.0.1:6379> lrange key2 0 -1
(empty array)
127.0.0.1:6379> exists key2
(integer) 0

rpush 和 rpushx

rpush 和 rpushx 这一组命令和lpush 和 lpushx用法基本一致,但是表示的并不是头插了,表示的是尾插。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> rpush key 5 6 7 8
(integer) 8
127.0.0.1:6379> lrange key 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
-- rpushx 有则尾插,无则不操作
127.0.0.1:6379> rpushx key 9 10 11 12
(integer) 12
127.0.0.1:6379> lrange key 0 -1
 1) "1"
 2) "2"
 3) "3"
 4) "4"
 5) "5"
 6) "6"
 7) "7"
 8) "8"
 9) "9"
10) "10"
11) "11"
12) "12"
127.0.0.1:6379> rpushx key2 1 2 3 4
(integer) 0
127.0.0.1:6379> lrange key2 0 -1
(empty array)
127.0.0.1:6379> exists key2
(integer) 0

lpop 和 rpop

lpop : 从list左侧取出元素(即头删)

rpop : 从list右侧取出元素(即尾删)

操作:LPOP key

操作:RPOP key [count]

LPOP 和 RPOP。从redis6.2版本,新增了一个count参数。count就描述这次要删几个元素。

返回值:取出的元素或者nil

时间复杂度:O(1)

127.0.0.1:6379> flushall
OK
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"
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"
127.0.0.1:6379> lpop key
"3"
127.0.0.1:6379> lpop key
"4"
127.0.0.1:6379> lrange key 0 -1
(empty array)
127.0.0.1:6379> lpop key
(nil)
-- rpop
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"
127.0.0.1:6379> rpop key
"4"
127.0.0.1:6379> lrange key 0 -1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> rpop key
"3"
127.0.0.1:6379> rpop key
"2"
127.0.0.1:6379> rpop key
"1"
127.0.0.1:6379> lrange key 0 -1
(empty array)
127.0.0.1:6379> rpop key
(nil)

lindex 和 linsert ,llen

lindex:给定下标,获取到对应的元素.

语法:LINDEX key index

返回值:取出的元素。如果下标非法,返回的是nil

linsert:在特定位置插入元素

语法:LINSERT key <BEFORE/AFTER> pivot element

BEFORE:指定位置之前

AFTER:指定位置之后

返回值是插入之后,得到的新的list的长度。

时间复杂度:O(N) 此处N指的是list中的元素个数。

如果要插入的列表中,基准值存在多个,怎么办?

linsert进行插入的时候,要根据基准值,找到对应的位置.从左往右找,找到第一个符合基准值的位置即可.

llen 命令:获取list⻓度

127.0.0.1:6379> rpush key 1 2 3 4 5 6 7 8
(integer) 8
127.0.0.1:6379> lindex key 3
"4"
127.0.0.1:6379> lindex key -1
"8"
127.0.0.1:6379> lindex key 100
(nil)
-- linsert命令
127.0.0.1:6379> linsert key before 4 100
(integer) 9
127.0.0.1:6379> lrange key 0 -1
1) "1"
2) "2"
3) "3"
4) "100"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
127.0.0.1:6379> linsert key after 4 200
(integer) 10
127.0.0.1:6379> lrange key 0 -1
 1) "1"
 2) "2"
 3) "3"
 4) "100"
 5) "4"
 6) "200"
 7) "5"
 8) "6"
 9) "7"
10) "8"
-- linsert进行插入的时候,要根据基准值,找到对应的位置.从左往右找,找到第一个符合基准值的位置即可.
127.0.0.1:6379> rpush key 4
(integer) 11
127.0.0.1:6379> lrange key 0 -1
 1) "1"
 2) "2"
 3) "3"
 4) "100"
 5) "4"
 6) "200"
 7) "5"
 8) "6"
 9) "7"
10) "8"
11) "4"
127.0.0.1:6379> linsert key before 4 300
(integer) 12
127.0.0.1:6379> lrange key 0 -1
 1) "1"
 2) "2"
 3) "3"
 4) "100"
 5) "300"
 6) "4"
 7) "200"
 8) "5"
 9) "6"
10) "7"
11) "8"
12) "4"
-- llen命令
127.0.0.1:6379> llen key
(integer) 12
127.0.0.1:6379> llen key2
(integer) 0

lrem

Irem: 删除列表中的元素
rem => remove

语法:LREM key count element

  • count :要删除的个数
  • element : 要删除的值
    • count > 0 从左往右删,
    • count < 0 从右往左删
    • count = 0 删除全部

准备工作:

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 8
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 12
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 16
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"
 9) "1"
10) "2"
11) "3"
12) "4"
13) "1"
14) "2"
15) "3"
16) "4"

代码案例:

删除左侧两个元素。

127.0.0.1:6379> lrem key 2 1
(integer) 2
127.0.0.1:6379> lrange key 0 -1
 1) "2"
 2) "3"
 3) "4"
 4) "2"
 5) "3"
 6) "4"
 7) "1"
 8) "2"
 9) "3"
10) "4"
11) "1"
12) "2"
13) "3"
14) "4"

删除右侧两个元素。

127.0.0.1:6379> lrem key -2 1
(integer) 2
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"
 9) "2"
10) "3"
11) "4"
12) "2"
13) "3"
14) "4"

删除全部:

127.0.0.1:6379> lrem key 0 1
(integer) 4
127.0.0.1:6379> lrange key 0 -1
 1) "2"
 2) "3"
 3) "4"
 4) "2"
 5) "3"
 6) "4"
 7) "2"
 8) "3"
 9) "4"
10) "2"
11) "3"
12) "4"

ltrim 和 lset

ltrim

语法:LTRIM key start stop

含义:保留start和stop之间区间内的元素(区间外面两边的元素就直接玻删除了)

lset

语法:LSET key index element

含义:根据下标,修改元素

如果输入的index非法,会直接报错。lindex可以很好从处理下标越界的情况,直接返回nil。lset来说则会报错,不会像js那样,直接在10这个下标这里搞出个元素来。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> rpush key 1 2 3 4 5 6 7 8
(integer) 8
127.0.0.1:6379> ltrim key 2 5
OK
127.0.0.1:6379> lrange key 0 -1
1) "3"
2) "4"
3) "5"
4) "6"
-- lset 命令
127.0.0.1:6379> lset key 2 100
OK
127.0.0.1:6379> lrange key   0 -1
1) "3"
2) "4"
3) "100"
4) "6"
-- 如果越界就会报错
127.0.0.1:6379> lset key 10 200
(error) ERR index out of range

阻塞版本的命令brpop和blpop

阻塞:当前的线程,不走了,代码不继续执行了.会在满足一定的条件之后,被唤醒。

如果list中存在元素,blpop和brpop就和lpop 以及rpop作用完全相同。如果list中为空,blpop和brpop就会产生阻塞.一直阻塞到队列不空为止。

但阻塞版本会根据timeout,阻塞一段时间。期间Redis可以执行其他命令。此处的blpop和brpop看起来
好像耗时很久,但是实际上并不会对redis服务器产生负面影响。

  • 命令中如果设置了多个键,那么会从左向右进行遍历键,一旦有一个键对应的列表中可以弹出元素,命令立即返回。
    • blpop和brpop都是可以同时去尝试获取多个key的列表的元素的。
    • 多个key对应多个list。这多个list哪个有元素了,就会返回哪个元素。
  • 如果多个客户端同时针对同一个键执行pop,则最先执行命令的客户端会得到弹出的元素。

语法:BLPOP key [key …] timeout

  1. 针对一个非空的列表进行操作
127.0.0.1:6379> flushall 
OK
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> blpop key 0
1) "key"
2) "1"

返回的结果相当于一个pair(二元组),一方面是告诉我们当前的数据来自于哪个key。一方面告诉我们取到的数据是什么。

  1. 针对一个空的列表进行操作
-- 客户端1:
127.0.0.1:6379> del key
(integer) 1
127.0.0.1:6379> keys *
(empty array)
-- 针对一个空表进行取元素,等待时间为100s,进行阻塞
-- 等另一个客户端进行添加元素的时候,就会停止阻塞,取出元素
127.0.0.1:6379> blpop key 100
1) "key"
2) "1"
(53.95s)
-- 客户端2
127.0.0.1:6379> rpush key 1 2 3 4
(integer) 4
  1. 针对多个key进行操作.
-- 客户端1:
127.0.0.1:6379> flushall
OK
-- 取出多个key中任意一个key的元素,此时所有key均为空
-- 当任意一个key有值的时候,就取出元素。
127.0.0.1:6379> blpop key key2 key3 key4 500
1) "key2"
2) "1"
(41.50s)
-- 客户端2:
127.0.0.1:6379> lrange key 0 -1
(empty array)
127.0.0.1:6379> lrange key2 0 -1
(empty array)
127.0.0.1:6379> lrange key3 0 -1
(empty array)
127.0.0.1:6379> lrange key4 0 -1
(empty array)
-- 四个key均为空,在key2中放入key值
127.0.0.1:6379> rpush key2 1
(integer) 1

brpop效果和blpop完全一样(这里是尾删了),就不再赘述了。

list类型的编码

在老版本的redis中编码分为ziplist(压缩列表)和linkedlist(链表)。把数据按照更紧凑的压缩形式进行表示的节省空间。当元素个数多了,操作起来效率会降低。在redis5及其之后,使用的是quicklist相当于是链表和压缩列表的结合.整体还是一个链表,链表的每个节点,是一个压缩列表.每个压缩列表,都不让它太大。同时再把多个压缩列表通过链式结构连起来

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> lpush key 1 2 3 4
(integer) 4
127.0.0.1:6379> object encoding key
"quicklist"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值