当前位置: 首页 > news >正文

第三章:掌握 Redis 存储与获取数据的核心命令

一.Redis 存储与获取数据的核心命令

1.1GET和SET

set 命令:用于将键值对存储到 Redis 中。

  • 语法:set key value
  • 说明:key 和 value 都是字符串类型。在使用时,key 和 value 可以不加引号,直接表示字符串;当然,也可以给它们加上单引号或者双引号。

get 命令:根据键从 Redis 中获取对应的值。

  • 语法:get key
  • 说明:如果指定的 key 不存在,会返回nil,它和 null 或 NULL 意思相同,表示没有值。

必须先进入 redis-cli 客户端程序,才能输入 Redis 命令。进入成功后,会显示类似 127.0.0.1:6379> 的提示符。

Redis 中的命令不区分大小写。例如,SET key value 和 set key value 效果是一样的


 1.2KEYS

keys 命令用于查询当前服务器上匹配指定模式(pattern)的键。可以通过一些特殊符号(通配符)来描述键的模样,匹配该模样的键会被查询出来。 

  • pattern 是包含特殊符号的字符串,有的地方将其翻译成 “样式” 或者 “模式”。它存在的意义是去描述另外的字符串长什么样。

?:匹配任意一个字符。

127.0.0.1:6379> keys h?llo
1) "hello"
2) "hallo"
3) "hbllo"

*:匹配 0 个或者多个任意字符。

127.0.0.1:6379> keys h*llo
1) "hllo"
2) "hello"
3) "hallo"
4) "hbllo"
5) "heeeeeeeello"

[abcde]:只能匹配到 a、b、c、d、e,其他字符不行,相当于给出固定的选项。

127.0.0.1:6379> keys h[abe]llo
1) "hello"
2) "hallo"
3) "hbllo"

[^e]:排除 e,只有 e 匹配不了,其他字符都能匹配。

127.0.0.1:6379> keys h[^ae]llo
1) "hbllo"


[a-b]:匹配 a 到 b 这个范围内的字符,包含两侧边界。

127.0.0.1:6379> keys h[a-e]llo
1) "hello"
2) "hallo"
3) "hbllo"


使用keys注意事项:
时间复杂度:keys 命令的时间复杂度是 O(N),其中 N 是数据库中键的数量。
生产环境禁用:在生产环境上,般都会禁止使用 keys 命令,尤其是 keys *(该命令会查询 Redis 中所有的键)。

  • 因为生产环境上的键可能会非常多,而 Redis 是一个单线程的服务器。执行 keys * 的时间会非常长,这会使 Redis 服务器被阻塞,无法给其他客户端提供服务。
  • 因为Redis 经常用于做缓存,挡在 MySQL 前面。如果 Redis 被 keys * 阻塞住,此时其他的查询 Redis 操作就会超时,这些请求就会直接查询数据库。如果突然有一大波请求过来,MySQL 可能会因为无法及时处理而挂掉,进而导致整个系统基本瘫痪。 

mysql数据库要是会说话:哇去,怎么一下子来这么多请求啊,顶不住啊,redis兄弟你死哪去了!

哈哈


 1.3EXISTS 

`exists` 命令用于判定指定的键(`key`)是否存在。 

  1. EXISTS key [key ...]
  2. 可以同时判定一个或多个键是否存在,返回存在的键的个数。例如,如果判定的三个键中有两个存在,就会返回 `2`。
  3. 在 Redis 这种键值对存储的体系(类似于哈希表)中,键(`key`)是唯一的。
  4. `exists` 命令的时间复杂度是 `O(1)`,这是因为 Redis 是按照哈希表的方式来组织这些键的,哈希表的查找操作时间复杂度为 `O(1)`。
  5. Redis 支持很多数据结构,指的是一个值(`value`)可以是一些复杂的数据结构。同时,Redis 自身的这些键值对是通过哈希表的方式来组织的,而 Redis 具体的某个值又可以是一些数据结构。

重点:

Q:一次查询多个,和一次查询一个有什么区别吗?

A:redis本质还是一个服务器,也是需要通过网络通信再来操作内存的

若分开执行命令会增加网络通信轮次,效率低、成本高。网络通信时数据需经历多层封装与分用过程,且网卡特性、客户端和服务器的位置等因素也会影响通信效率。不过 Redis 很多命令支持一次操作多个键或多种操作,以此减少网络通信轮次,提升效率。


 1.4DEL


1. 作用:`del`(即 `delete`)命令用于删除指定的键(`key`)。
2. 语法:DEL key [key ...]。可以一次删除一个或者多个键。
3. 时间复杂度:`O(1)`。
4. 返回值:返回删除掉的键的个数。例如:

   127.0.0.1:6379> del hllo(integer) 1127.0.0.1:6379> del hello hallo aaa(integer) 2

举个栗子~

 

重点关注: 
平常在学习 MySQL 时,像 `drop database`、`drop table`、`delete from......` 这类删除操作都是非常危险的,一旦执行删除,数据就会丢失,而对于redis的删除,情况是否严重就看redis作为什么


1.Redis 作为缓存时的删除操作:
Redis 主要应用场景之一是作为缓存,此时 Redis 里存的只是热点数据,全量数据在 MySQL 数据库中。如果只是删除 Redis 中的几个键,一般问题不大。但如果把所有数据或者一大部分数据都删除,影响会很大。因为原本 Redis 是帮助 MySQL 分担压力的,Redis 没数据了,大部分请求会直接打到 MySQL 上,容易导致 MySQL 崩溃。


2.Redis 作为数据库时的删除操作:
如果把 Redis 作为数据库使用,此时误删数据的影响会很大。


3.Redis 作为消息队列(mq)时的删除操作:
如果把 Redis 作为消息队列(mq),误删数据的影响大小需要根据具体情况判断。


1.5EXPIRE

Redis 的 expire 命令用于给指定的键(key)设置过期时间,时间单位是秒,当键的存活时间超出设定值,就会被自动删除。

expire 命令的语法是 EXPIRE key seconds,需要注意的是,此处设置过期时间必须针对已经存在的键,设置成功返回 1,设置失败返回 0,时间复杂度为 O(1)。
另外还有 pexpire 命令,它以毫秒为时间单位设置过期时间。

举个栗子~

在很多业务场景中,时间限制是很常见的,比如手机验证码通常 5 分钟内有效,点外卖的优惠券也在指定时间内有效。基于 Redis 实现分布式锁时,为避免不能正确解锁的情况,也会在加锁时设置过期时间(Redis 分布式锁就是在 Redis 里写一个特殊的键值对)。


*1.6TTL

ttl(time to live)命令用于查看当前键的过期时间还剩多少。

pttl 命令也用于查看过期时间剩余,但时间单位是毫秒。

需要说明的是,网络原理中 IP 协议报头里也有一个 TTL 字段,但 IP 中的 TTL 不是用时间衡量过期,而是用次数。

重点关注: 

 redis整体的key过期策略是怎么实现的?

Redis 的 key 过期策略主要通过定期删除和惰性删除两种策略结合实现。

  • 定期删除是指 Redis 每次抽取一部分 key 进行过期时间验证,保证抽取检查过程足够快,因为 Redis 是单线程程序,若扫描过期 key 耗时太久,会阻塞正常请求处理;
  • 惰性删除则是在访问某个 key 时,若发现其已过期,就触发删除操作并返回 nil。不过这两种策略结合整体效果一般,仍可能有过期 key 残留。

另外,Redis 没有采用定时器方式实现过期 key 删除,因为基于定时器实现易引入多线程,而 Redis 早期版本奠定了单线程基调,引入多线程会打破最初设计(无官方回答,猜测)。

若有多个 key 过期,可通过基于优先队列或时间轮的定时器来高效处理。那讲讲定时器吧

优先级队列/堆实现定时器:

Redis 处理过期 key 可借助优先级队列,按过期时间排序,队首是最早过期的 key。用一个线程检查队首元素,未过期则后续元素也没过期,无需全扫描。线程根据队首过期时间设置等待,避免频繁检查浪费 CPU,有新任务时再调整。

基于时间轮实现定时器:

假设我们把时间轮的每个小段设置为 100ms,整个时间轮有 10 个格子,代表 1000ms(1 秒)的时间范围。

  • 现在有一个 key,它会在 300ms 之后过期,我们就把这个 key 对应的任务添加到时间轮中第 3 个格子(因为 3×100ms = 300ms)所挂的链表中。
  • 时间轮的指针每隔 100ms 移动一格,当指针移动到第 3 个格子时,就会执行这个格子链表中的任务,也就是处理这个过期的 key。
  • 再比如有一个 key 要在 3000ms 之后过期,因为 3000ms ÷ 100ms = 30,时间轮只有 10 个格子,30 mod 10 = 0,所以我们可以把这个 key 对应的任务添加到第 0 个格子的链表中,并且记录这个任务需要在指针绕时间轮 3 圈后执行。当指针第 3 次移动到第 0 个格子时,就会执行这个任务。

举一个栗子~ 

 就像老式挂历,每页代表 1 天(时间小段),上面记着当天要做的事(任务链表)。每天早上(固定间隔)翻一页(指针移动),然后处理这一页上的所有事情。如果要记一个 3 天后的事,就写在第 3 页;若事情在 1 个月后,就按挂历页数循环,到对应那页再处理。挂历的每页天数(格子时间)和总页数(格子数量)可根据需要选,比如用周历(每页 1 周)或月历(每页 1 月)。

需注意的是,Redis 并没有采用上述两种方案,但这两种方案是高效定时器的实现方式,在很多场景中会用到。另外,Redis 源码中有一个核心机制是事件循环。


1.7TYPE

1.Redis 键值对的值类型及对应实现

返回 key 对应的数据类型。

键(key)对应的值(value)可以是多种类型:

  • 字符串:如 “It is a string or a byte stream”,类似C++ 的 std::string 和 Java 的 String。
  • 哈希:如包含 field1 - value1、gender - female 等键值对的结构,类似C++ 的 std::unordered_map 和 Java 的 HashMap。
  • 列表:如包含 a、b、甲、乙的结构,类似C++ 的 std::deque 和 Java 的 List。
  • 集合:如包含苹果、香蕉、葡萄的结构,类似C++ 的 std::set 和 Java 的 Set。
  • 有序集合:如包含关羽(99.0)、刘备(87.2)、张飞(93.0)的结构,除存储成员外还存储权重分数,Redis 中对应特定实现。

2.Redis 数据结构的底层优化与实现
Redis 在底层实现上述数据结构时,会在源码层面针对实现进行特定优化,以达到节省时间和空间的效果。内部具体实现的数据结构存在变数,即编码方式。Redis 承诺哈希表的查询、插入、删除操作时间复杂度为 O (1),但背后实现不一定是标准哈希表,可能在特定场景下使用其他数据结构,仍保证时间复杂度符合承诺。(就是你使用redis的时候,reids会根据场景进行内部调优,即使用不同的编码方式)


3.Redis 数据类型与内部编码方式

数据结构:Redis 承诺的数据类型,也可理解为数据类型。

编码方式:Redis 内部底层的实现,Redis 会自动适应,程序在使用 Redis 时一般感知不到。同一个数据类型背后可能有不同编码实现方式,会根据特定场景优化。
string 类型

  • 内部编码有 raw(最基本的字符串,底层是 C++ 的 char 数组或 Java 的 byte 数组)、
  • int(当 value 是整数时,Redis 直接用 int 保存,可实现计数功能)、
  • embstr(针对短字符串的特殊优化)

hash 类型

  • 内部编码有 hashtable(最基本的哈希表,Redis 内部的哈希表实现)
  • ziplist(哈希表元素较少时可能优化成 ziplist,压缩列表能节省空间,因为 Redis 有很多 key,若 key 对应 hash 不大,压缩可减少内存占用)


list 类型内部编码有 linkedlist、ziplist。
set 类型内部编码有 hashtable、intset。
zset 类型内部编码有 skiplist、ziplist。

注:C++ 里的 char 是 1 字节,等价于 Java 的 byte;Java 的 char 是 2 字节。Java 标准库中的 HashTable 与 Redis 内部哈希表实现思想一致但具体实现可能不同。


http://www.xdnf.cn/news/1180819.html

相关文章:

  • MNIST 手写数字识别模型分析
  • 秋叶sd-webui频繁出现生成后无反应的问题
  • 【Web APIs】JavaScript 节点操作 ⑧ ( 删除节点 - removeChild 函数 | 删除节点 - 代码示例 | 删除网页评论案例 )
  • 算法竞赛阶段二-数据结构(34)数据结构链表STL vector
  • 【PyTorch】图像二分类项目-部署
  • Spring Boot 3整合Spring AI实战:9轮面试对话解析AI应用开发
  • HttpServletRequest深度解析:Java Web开发的核心组件
  • PyTorch数据选取与索引详解:从入门到高效实践
  • Vue3 面试题及详细答案120道(91-105 )
  • 开立医疗2026年校园招聘
  • 论文复现-windows电脑在pycharm中运行.sh文件
  • 工具篇之开发IDEA插件的实战分享
  • C# 方法执行超时策略
  • 处理URL请求参数:精通`@PathVariable`、`@RequestParam`与`@MatrixVariable`
  • Lua元表(Metatable)
  • Python 使用环境下编译 FFmpeg 及 PyAV 源码(英特尔篇)
  • TDengine 转化类函数 TO_CHAR 用户手册
  • 【数字IC验证学习------- SOC 验证 和 IP验证和形式验证的区别】
  • 借助 VR 消防技术开展应急演练,检验完善应急预案​
  • 数据库底层索引讲解-排序和数据结构
  • 主流 BPM 厂商产品深度分析与选型指南:从能力解析到场景适配
  • 基于深度学习的CT图像3D重建技术研究
  • Python-初学openCV——图像预处理(二)
  • MySQL 表的操作
  • 大模型Prompt优化工程
  • Shell的正则表达式
  • JVM原理及其机制(二)
  • Web前端:JavaScript findIndex⽅法
  • MySQL数据库迁移至国产数据库测试案例
  • Spring MVC 统一响应格式:ResponseBodyAdvice 从浅入深