【Redis】常用命令

在学习命令之前,我们一定要参考Redis的官网,能够看英文官方文档,是每个程序员的"基操".

🐼Redis最核心的命令

我们说过,Redis是按照键值对的方式来存储数据的。

GET

cpp 复制代码
GET key

通过key获取value, 如果 key 不存在,返回 nil。如果 value 的数据类型不是 string,会报错。时间复杂度O(1)

SET

cpp 复制代码
SET key value 

设置键值对[key, value], 将 string 类型的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么。之前关于此 key 的 TTL 也全部失效。时间复杂度O(1)

不管是set还是get,其中key和value都是字符串

Redis不区分大小写,和MySQL一样。

为什么他俩是最核心的两个命令吗,不就是一个读,一个写,与Redis通过网络进行IO,通过这两个O(1)时间复杂度的操作,我们就能完成绝大部分操作了。


🐼Redis全局命令

我们说了,Redis是键值对结构,其中key是固定字符串,其中value表示很多数据结构类型,Redis 有 5 种数据结构,不过对于键来说有⼀些通用的命令,而value对于不同的容器我们到时候再去看。

而全局命令就是,能够搭配任何一个数据结构去使用的命令

✅KEYS

返回所有满足样式(pattern)的 key,该命令可以看到的是每一个key的模样,同时也可以允许存在通配符等,当我们不确定我们的redis中有哪些key时,可以试着来查找

cpp 复制代码
KEYS pattern

来看一下官网给的pattern的介绍,主要是一些通配符的匹配规则,忘记了去官网查即可。

cpp 复制代码
h?llo matches hello, hallo and hxllo  # ?表示匹配任意一个字符。
h*llo matches hllo and heeeello # *表示可以匹配一个或者多个任意个字符。
h[ae]llo matches hello and hallo, but not hillo # [....]表示可以从中匹配这些字符,不再[]中的字符不行。
h[^e]llo matches hallo, hbllo, ... but not hello # 表示除e的字符其他都行
h[a-b]llo matches hallo and hbllo # 表示匹配 [a, b]之间的字符,包括边界

注意事项:

keys的时间复杂度为O(N),因此,不建议使用keys,在生产环境上,明确禁止使用keys,尤其是像keys * 这样的导致Redis挂掉的命令

🚩为啥嘞,首先生产环境就是线上环境,就是和用户交互的环境,你在线上环境搞个这,因为Redis是基于网络的,是客户端服务器的模式,而且Redis是单线程的,又不单单是服务你一个客户端,如果你这个客户端发一个key*,导致Redis只为你一个人服务了,导致其他用户的访问都去MySQL那里了,MySQL它又很"娇气",一不小心就挂了,所以,强烈禁止,不要让站在MySQL背后的哪个男人-Redis阻塞住!它在为MySQL负重前行嘞!

**✅**EXISTS

判断KEY是否存在

cpp 复制代码
EXISTS key [key ...]

返回值为Key存在的个数,也就是我们可以一次性判断多个key是否存在,存在几个就返回几!

时间复杂度为O(1),官网写的是O(N)其中这个N就是key的个数,这个N是多少,不好说,但你一次性要判断的KEY不能特别多对吧,所以就是O(1).

注意下面这两种写法的区别:

🚩第一种写法和第二种分两次写,有啥区别吗?

其实,有本质的区别,我们知道我们的redis是客户端服务器通信的,我们每操控的一条命令,都是基于网络发给redis-server的,然后redis-server处理完再发给我们。相比于操控在内存,是很慢的,走网络就有开销,比如os什么时候刷新网卡?网卡IO效率还慢,还得封装分用。那么你说一次命令完成的事情,走两次,哪个好?

redis也意识到了这一点,所以redis支持一次性一个命令来操作多个key完成多种操作。

✅DEL

删除指定的 key

cpp 复制代码
DEL key [key ...]

返回值依旧是成功删除掉key的个数。时间复杂度为O(1)

🚩这里需要注意一下,就是之前学的MySQL,是很忌讳你去删除东西的,这里Redis呢?在Redis中删除东西,要看你Redis是缓存还是被当做数据库使用了,如果你仅仅是一个热点数据,全量数据在MySQL中,那么删除几个key,问题不大,不过删多了,可能导致热点数据命中率不高,进而导致MySQL挂掉。但是如果Redis被当做数据库使用,那么此时就不敢随意删除了,一旦删除,可能不能进行回滚操作,导致数据丢失了~归根结底,还是不要乱删数据!

✅EXPIRE

为已经存在指定的 key 添加秒级的过期时间(Time To Live TTL)

返回1表示设置成功。0 表示设置失败。时间复杂度为O(1)

cpp 复制代码
EXPIRE key seconds

怎么理解这个过期时间,就是如果你的key超过这个过期时间,就会被自动删除~

✅TTL

全称为time to live

获取已经存在的指定 key 的过期时间,秒级

返回值:剩余过期时间。-1 表示没有关联过期时间,-2 表示key 不存在。时间复杂度为O(1)

cpp 复制代码
 TTL key

通长这个命令配合expire来使用,来查看过期时间的。

✅TYPE

返回 key 对应value的数据类型

时间复杂度为O(1)

cpp 复制代码
TYPE key

返回值包括: returned are: string, list, set, zset, hash, stream, and vectorset.

对于以上value的操作,操作差别很大, 命令是完全不同的,但是我们都可以使用type来看看对应的key的value到底是啥~


🐼扩展知识(面试题)

Redis中的key的过期时间是怎么实现的?Redis中的key那么多,你怎么知道哪些key要被删除,哪些key不被删除,哪些key还没过期?如果我们直接遍历所有的key,那么"杀伤力"不亚于key *

主要有两种方式:

✅定期删除

每次抽取一部分,进行验证过期时间,保证这个抽取过程是足够快的!为什么要保证足够快呢?或者说为什么要进行抽取呢?原因是Redis是单线程程序,主要任务是执行每个命令的任务,如果抽取过程占用的时间太久,导致其他客户端的连接是阻塞的,就类似与执行key*咯

✅惰性删除

假设这个key已经过期,但是暂时还没删它,key还存在,紧接着,redis-cli后面又再一次访问到了这个key,然后再将它删除,并返回给客户端nil。

虽然上述两种操作可以删除过期的key,但是效果一般,并不能保证所有key及时删除。不过redis进行了一写淘汰策略的机制。


这里有一个有意思的故事:

为什么没有使用定时器?

网上有人说,Redis的删除key的策略如果是根据定时器来完成的,那么不靠谱。真的是这样吗?

其实不然,Redis的作者并没有实现定时器,猜测因为Redis完全就是一个线程的基调,引入定时器,就意味着引入了多线程。为了不打破作者的初衷,这里并没有引入多线程。也没有引入定时器了!

定时器真的不靠谱吗?我们来看一下常用的两种定时器:

⌚️根据优先级队列实现的定时器

优先级队列就是按照指定的优先级进行先入先出的,啥叫优先级高,自定义的~

在redis删除key的场景中,就可以通过"过期时间越早,优先级越高的方式",那么队首元素,就是最早的key,最先过期的,所以我们只需要分配一个线程,取出队首元素,看看是不是需要删除即可,如果队首都没过期,那么所有key都没过期~此时,我们就不需要遍历key了

⌚️根据时间轮来实现定时器

把时间划分为一个个小段,就是一个小格子,小段的粒度,看具体的场景。比如,将时间段为每100ms一次,而每一个格子上挂接这一个个链表,这一个个链表的节点,可能是 一个任务,每隔100ms,小格子都移动一格,尝试把对应任务执行一下,如图:

如果删除key操作使用定时器看起来是高效的,而没有使用定时器也不是网上所说的,还是Redis的初衷就是单线程的基调~

相关推荐
Zsr10231 小时前
MySQL 主从同步与读写分离:构建高性能、高可用数据库架构
数据库·mysql
老华带你飞1 小时前
房屋租赁管理|基于springboot + vue房屋租赁管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·毕设
踢球的打工仔1 小时前
mysql多表关联
数据库·mysql
少许极端1 小时前
Redis入门指南:从零到分布式缓存(一)
redis·分布式·缓存·微服务
IvorySQL1 小时前
Postgres 18:Skip Scan - 摆脱最左索引限制
数据库·postgresql·开源
瀚高PG实验室2 小时前
审计日志(audit_log )文件过大
数据库·瀚高数据库
tzhou644522 小时前
MySQL主从复制与读写分离:从原理到实战
数据库·mysql·adb
爬山算法2 小时前
Redis(161)如何使用Redis实现分布式锁?
数据库·redis·分布式
可可苏饼干2 小时前
NoSQL 与 Redis
数据库·redis·笔记·学习·nosql