Redis:通用命令 & 数据类型
- 通用命令
- SET
- GET
- KEYS
- EXISTS
- DEL
- EXPIRE
- TTL
- TYPE
- FLUSHALL
- 数据类型
Redis
的客户端提供了很多命令用于操控Redis
,在Redis
中,key
的类型都是字符串,而value
有多种类型,每种类型都有自己的操作命令,但是也有一些与类型无关的命令,称为通用命令
。
本博客讲解Redis
中的通用命令以及数据类型。
redis
的命令不区分大小写,由于小写可读性更好,所以博客后续使用小写。
通用命令
SET
- 设置一个键值对
set key value
此处要求key
和value
都是字符串,可以加单引号或双引号,也可以不加。
GET
- 获取键对应的值
get key
此处由于先前以及插入了key1
,成功查询到value1
。如果查询不存在的值,会返回nil
,这表示不存在,相当于C语言的NULL
。
KEYS
- 获取所有满足正则的
key
keys pattern
常见的正则符号:
?
:匹配一个任意字符*
:匹配任意多个任意字符[abc]
:只能匹配a
、b
、c
三者之一,匹配一次[^a]
:排除e
,其它的都能匹配,匹配一次[a-c]
:匹配a
到c
范围内的字符,匹配一次
再多的正则匹配法则就不讲解了,以上五个是官方给出的五种匹配法则。
如图,一开始插入了四个键值对,随后根据以上五种正则进行匹配,筛选出了不同的key
。
要注意的是,keys
会遍历Redis
内部的所有数据,时间复杂度为O(N)
。生产环境中一般会禁止使用这个命令。
EXISTS
- 判断一个或多个
key
是否存在
exists key [key ...]
在exists
后可以跟着多个key
,最后返回存在的key
的个数。
因为底层使用哈希表组织数据,所以该操作的复杂度为O(1)
。
上例中,先同时查询了hallo
和hello
,返回2
说明两个都存在。后面又分别查询两者。
问题来了,同时查询多个key
和分开查询有什么区别吗?
其实区别可大了,因为Redis
是基于网络实现的,客户端敲入的每一个命令都要包装为一个请求发给客户端,客户端再进行响应。如果一次性查询多个key
,一次请求就可以完成查询,而多次查询则需要多个网络请求,效率会低很多。
因为网络要与硬件进行IO
,封装层数多,速度是非常慢的。这是Redis
的缺陷,因此Redis
在设计时,就尽可能支持让一个命令完成多个操作。
DEL
- 删除指定的
key
del key [key ...]
同样的,del
也支持多个key
同时删除。
EXPIRE
- 为指定的
key
添加秒级的过期时间
expire key seconds
所谓过期时间
,就是一个数据的有效期,当数据超过过期时间,数据就会被自动删除。比如说常见的验证码,就可以用这个过期时间实现。
返回1
表示成功,0
表示失败,如果对不存在的key
设置过期时间,就会失败。
如图,设置了一个hello
变量,并设置过期时间为5 s
,随后立刻查询,可以查询到hello
,再过一段时间就被自动删除了,查询结果为nil
。
如果想要更加精确的时间,可以使用pexpire
命令,该命令的时间单位是毫秒。
TTL
- 获取
key
的秒级过期时间
ttl key
如果key
没有过期时间,返回-1
,如果key
不存在,返回-2
,其他情况返回剩余时间。
如图,设置hello
后,查询ttl
,由于key
没有设置过期时间,此时返回-1
。设置过期时间为5 s
,后两次查询分别查询到4
、1
,为剩余的过期时间。最后一次查询结果为-2
,表示key
不存在,因为已经过期删除了。
另外的,ttl
也有毫秒级别的指令pttl
。
那么Redis
是如何实现定期删除的?
此处采用了定期删除
+惰性删除
的策略:
定期删除
:每隔一段时间,抽取一部分数据检查,看是否有过期的数据,将其删除惰性删除
:当用户操作数据时,检测一遍这个数据是否过期,如果过期就删除,再给用户返回key
不存在
因为Redis
内部要存储不少数据,轮询一遍所有数据要浪费很多时间,所以不会遍历所有数据判断过期。而是等待用户访问数据才删除,或者抽样检查删除,以降低删除过期数据带来的时间浪费。
TYPE
- 返回
key
对应的value
的类型
type key
在Redis
中,所有的key
都是字符串类型,而value
有多种类型。如果返回none
表示key
不存在。
FLUSHALL
- 删除
Redis
中所有数据
flushall
这个命令在生产环境中千万不要敲,这就是删库操作,只是在学习过程中可能要清除以前的数据,才需要用到。
数据类型
官方文档中,给出了以下基础数据类型:
String
:字符串Hash
:哈希List
:列表Set
:集合Sorted set
:有序集合Stream
:流Bitmap
:位图Bitfield
:位字段Geospatial
:地理信息
除此之外,Redis
还支持一些其它的扩展类型。在基础类型中,最常用的是前五种类型。
Redis
非常追求高效,在数据类型方面,向用户承诺这些数据类型使用起来可以达到指定效果,但是底层具体如何实现,这就不能保证了。就比如说哈希表,它保证用户用起来和哈希表没有区别,可以以O(1)
的时间复杂度完成增删查改,但是底层是不是使用哈希表,就不一定了!
每种数据类型,都可能会有多种实现方式,Redis
称其为编码方式,常见编码方式如下表:
数据类型 | 内部编码 |
---|---|
string | raw |
int | |
embstr | |
hash | hashtable |
ziplist | |
list | linkedlist |
ziplist | |
set | hashtable |
intset | |
zset | skiplist |
ziplist |
string
raw
:最基本的字符串,底层就是一个字符数组int
:当value
是一个整数,此时会用int
来保存embstr
:针对短字符串的优化
value
默认传入时都是字符串,如果检测到字符串是一个数字,就转为int
存储。比如说字符串"12345678"
,如果用字符串存储需要8 byte
,但是Redis
检测到其为整数后,转为int
存储,只需要4 byte
。
-
hash
hashtable
:标准的哈希表ziplist
:压缩列表,当哈希表元素比较少,可以通过该结构压缩空间
-
list
linklist
:标准的链表ziplist
:压缩列表,当链表元素比较少,可以通过该结构压缩空间
在Redis 3.2
后,list
统一使用quicklist
,取消了linklist
和ziplist
,因为quicklist
兼顾了两者的特性。简单来说,quicklist
基本结构是一个linklist
,而每一个链表节点是一个ziplist
,也就是说耦合了前两者。
set
hashtable
:基于哈希表实现的集合intset
:如果集合都是整数,会优化为该结构
在现代编程语言中,常会使用平衡二叉搜索树,比如红黑树来实现set
,其时间复杂度为O(lgN)
。但是Redis
为了更加高效,采用了O(1)
时间复杂度的哈希表实现set
。
zset
skiplist
:跳表ziplist
: 压缩列表,当集合元素比较少,可以通过该结构压缩空间
此处的跳表也是一种搜索结构,时间复杂度属于O(lgN)
级别,与平衡二叉搜索树属于同一级别。
如果想要查看数据类型底层具体使用了什么编码,可以使用指令object encoding
:
object encoding key
如图,同为string
类型的三个value
,最后底层编码使用了不同的方式。