
个人主页:一条泥憨鱼(欢迎各位大佬莅临)❄️《数据结构》 ❄️《AI与Agent那些事》❄️《从0开始学计算机网络》 ❄️《后端开发》前言想象你走进一个公共储物柜大厅。每个柜子有编号你凭编号打开柜子往里放东西或者取东西。Redis 差不多就是这个意思一个放在内存里的储物柜仓库你通过 key 这个编号去存取对应的 value。第一次接触 Redis 的话不用一上来就搞懂集群、持久化、哨兵这些东西。先把最基础的问题弄清楚怎么开门怎么存东西怎么找东西怎么分类管理。Redis入门Redis 是一个键值数据库。键值是什么意思它存数据的方式特别简单一个名字对应一份内容。名字叫 key内容叫 value。你给 Redis 一个 key它就还你对应的 value反过来你给它一个 key 加一个 value它就存进去了。储物柜上贴着标签标签写张三的雨伞柜子里放的就是那把雨伞。这里张三的雨伞就是 key雨伞就是 value。Redis 里也一样- key一个字符串比如 user:1:name- value可以是字符串、数字、列表、集合等等下面会一种一种讲那为什么大家都用 Redis一个字快。传统数据库比如 MySQL把数据存在硬盘上每次读写都要跟硬盘打交道硬盘的速度和内存比差了好几个数量级。Redis 把数据放在内存里读写几乎就是瞬间的事。代价是内存比硬盘贵而且断电后内存里的东西会丢——不过 Redis 有持久化机制那是后话。现在你只需要记住一件事Redis 就是一个用 key 找 value 的超高速储物柜。通用命令——不管什么类型都能用的“万能钥匙”Redis 的命令有几百个但有一部分命令不管你存的是什么类型的数据都能用。这些就是通用命令。先学会它们你就能开始操作 Redis 了。KEYS列出所有 keyKEYS pattern把所有匹配某个模式的 key 列出来。# 列出所有 key危险后面会说为什么 KEYS * # 列出所有以 user: 开头的 key KEYS user:* 踩坑警告KEYS * 在生产环境千万不要用。Redis 是单线程处理命令的KEYS * 会遍历所有 key如果数据量大了几十万上百万这条命令会卡住整个 Redis其他请求全部排队等着。后面讲 SCAN 的时候会给替代方案。EXISTS判断 key 存不存在EXISTS key [key ...]EXISTS user:1:name # 返回 1 表示存在返回 0 表示不存在DEL删除 keyDEL key [key ...]DEL user:1:name # 返回被删除的 key 数量EXPIRE 和 TTL设置过期时间和查看剩余时间这两个命令经常配对使用。EXPIRE 给一个 key 设置存活时间到点了 Redis 自动删掉它。TTL 用来查看还剩多少时间。# 设置 user:1:token 这个 key 在 3600 秒后自动删除 EXPIRE user:1:token 3600 # 查看还剩多少秒 TTL user:1:token # 返回 3595 表示还剩 3595 秒 # 返回 -1 表示没设置过期时间 # 返回 -2 表示 key 已经不存在了存验证码、临时 token 这类过一段时间就没用的数据用这个功能特别合适。TYPE查看 key 是什么类型TYPE keyTYPE user:1:name # 返回 string TYPE user:1 # 可能返回 hash当你忘了某个 key 存的是什么类型的数据时TYPE 能帮你确认。Key 的层级格式——用冒号给数据“分文件夹”Redis 的 key 本质上就是一个字符串没有真正的目录结构。它不像你电脑里的文件夹可以一层套一层Redis 里所有 key 都是平铺的。但大家慢慢形成了一种约定用冒号 : 分隔模拟出层级的感觉。比如你要存用户 1 的名字、年龄、邮箱user:1:name - 张三user:1:age - 28user:1:email - zhangsanexample.com再比如订单数据order:100:status - paidorder:100:amount - 199.00order:101:status - pending这么做有几个好处。可读性强你一眼就能看出这个 key 属于哪个业务、哪条记录、哪个字段。要找用户 1 的所有信息匹配 user:1:*要找所有订单匹配 order:*。不同业务用不同前缀user:、order:、product:也不会互相打架。常见的命名规范大概是这样的业务名:对象ID:字段名或者更细一点业务名:对象类型:对象ID:字段名比如 shop:product:888:price。用 SCAN 代替 KEYS前面说了 KEYS * 在生产环境是禁忌。那怎么安全地找出某一类 key用 SCAN。SCAN 不会一次性返回所有结果而是分批次返回每次只返回一小部分。这样就不会长时间阻塞 Redis。# 从游标 0 开始扫描每次返回大约 10 个 key匹配 user:1:*SCAN 0 MATCH user:1:* COUNT 10返回结果类似1) 17 - 下一次扫描的游标 2) 1) user:1:name 2) user:1:age拿到游标 17 后继续用 SCAN 17 MATCH user:1:* COUNT 10直到游标回到 0表示扫完了。一开始你可能觉得这很麻烦但记住一点就行生产环境永远用 SCAN不用 KEYS。String 类型——最基础也最万能的“单格储物格”String 是 Redis 里最简单的类型。一个 key 对应一个字符串值就像储物柜里只有一个格子里面放一样东西。基本存取SET 和 GET# 存一个值 SET user:1:name 张三 # 取出来 GET user:1:name # 返回 张三就这么简单。存进去什么取出来就是什么。SETNX不存在才设置SETNX lock:order:100 1 # 如果 lock:order:100 不存在设置成功返回 1 # 如果已经存在设置失败返回 0SETNX 是 SET if Not eXists 的缩写。这个命令看起来不起眼但它能用来做分布式锁的入门版多个服务同时抢一个锁谁先 SETNX 成功谁就拿到锁其他人返回 0 就等着。当然真正的分布式锁还要考虑过期时间、误删等问题但 SETNX 是理解这件事的起点。INCR 和 DECR数字加减SET page:view:1001 0 INCR page:view:1001 # 返回 1 INCR page:view:1001 # 返回 2 DECR page:view:1001 # 返回 1 INCR 把值加 1DECR 减 1。这里有个很重要的点INCR 是原子操作。意思是哪怕有一万个请求同时执行 INCR page:view:1001结果也一定是准确的不会出现两个请求读到同一个值然后各自加 1 导致少算的情况。这就是为什么 Redis 的 INCR 特别适合做计数器——文章阅读量、点赞数、接口调用次数都可以用它。MSET 和 MGET批量存取# 一次存多个 MSET user:1:name 张三 user:1:age 28 user:1:email zsexample.com # 一次取多个 MGET user:1:name user:1:age user:1:email # 返回 # 1) 张三 # 2) 28 # 3) zsexample.com批量操作的好处是减少网络往返次数。存三个值用 SET 要发三次命令用 MSET 只发一次。Hash 类型——像一个“带多个小格子的抽屉”String 存一个对象的时候你得把整个对象序列化成字符串比如 JSON改一个字段也要把整个对象读出来、改完再写回去。Hash 解决了这个问题。Hash 的结构是一个 key 下面挂多个field-value 对。就像一个大抽屉里面分了小格子每个小格子放一个字段。# 返回 # 1) name # 2) 张三 # 3) age # 4) 28 # 5) email # 6) zsexample.com # 删除某个字段 HDEL user:1 email # 给某个数字字段加值 HINCRBY user:1 age 1 # 返回 29对比一下如果用 String 存用户信息你得 SET user:1 {name:张三,age:28}改年龄要把整个 JSON 解析出来改完再写回去。用 Hash 直接 HINCRBY user:1 age 1 就完事了。Hash 适合存对象的多个字段尤其是你经常只读写其中某几个字段的场景。List 类型——有序、可重复的“排队通道”List 就是一个有序列表像排队一样有头有尾元素可以重复。# 从左边塞入 LPUSH queue:task task1 LPUSH queue:task task2 # 现在列表是task2, task1 # 从右边塞入 RPUSH queue:task task3 # 现在列表是task2, task1, task3 # 从左边弹出 LPOP queue:task # 返回 task2 # 从右边弹出 RPOP queue:task # 返回 task3 # 查看列表范围0 到 -1 表示全部 LRANGE queue:task 0 -1 # 查看长度 LLEN queue:taskList 最典型的用法是消息队列生产者用 LPUSH 从左边塞任务消费者用 RPOP 从右边取任务先进先出。真正的消息队列要考虑更多东西确认机制、重试等但入门级场景完全够用。另一个常见用法是最新列表。比如最新 10 条评论每次来新评论用 LPUSH 塞进去再用 LTRIM 保留前 10 个。Set 类型——无序、不重复的“标签集合”Set 和 List 最大的区别有两个无序、不重复。你往里塞重复的元素它只会保留一个。# 添加标签 SADD article:1:tags redis database cache # 再加一个重复的不会生效 SADD article:1:tags redis # 返回 0表示没添加新元素 # 查看所有元素 SMEMBERS article:1:tags # 返回 redis, database, cache顺序不保证 # 判断某个元素在不在 SISMEMBER article:1:tags redis # 返回 1 # 删除元素 SREM article:1:tags cache Set 真正好用的地方在于集合运算。 bash # 用户 1 关注的人 SADD user:1:follows u2 u3 u4 # 用户 2 关注的人 SADD user:2:follows u3 u4 u5 # 共同关注交集 SINTER user:1:follows user:2:follows # 返回 u3, u4 # 所有关注并集 SUNION user:1:follows user:2:follows # 返回 u2, u3, u4, u5共同好友、共同兴趣标签、去重统计这些场景用 Set 非常自然。Sorted Set 类型——带排名的“排行榜”Sorted Set有序集合是在 Set 的基础上给每个元素额外绑了一个分数score。Redis 会根据分数自动给元素排序。# 添加玩家分数 ZADD rank:game 100 player1 ZADD rank:game 250 player2 ZADD rank:game 180 player3 # 按分数从低到高查看带分数 ZRANGE rank:game 0 -1 WITHSCORES # 返回 # player1, 100 # player3, 180 # player2, 250 # 按分数从高到低查看排行榜最常用 ZREVRANGE rank:game 0 -1 WITHSCORES # 返回 # player2, 250 # player3, 180 # player1, 100 # 查看某个玩家的分数 ZSCORE rank:game player2 # 返回 250 # 查看某个玩家的排名从低到高从 0 开始 ZRANK rank:game player2 # 返回 2 # 给某个玩家加分 ZINCRBY rank:game 50 player1 # 返回 150Sorted Set 最经典的用途就是排行榜游戏得分排名、热搜榜、销量排行。ZREVRANGE rank:game 0 9 就能拿到前十名。它还能用来做延时队列把任务的执行时间戳作为 score然后用 ZRANGEBYSCORE 取出到时间的任务。到这里Redis 最基础的部分过完了。通用命令管理 key冒号分层组织 key五种数据类型应付不同的存储需求。初学把文中的命令挨个敲一遍。敲完之后再去了解过期策略和持久化——那是保证数据不丢的关键但得先把基础操作练熟了再说。