首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么有人说 Redis 的 set 命令是一个危险命令?

为什么有人说 Redis 的 set 命令是一个危险命令?

作者头像
业余草
发布2019-11-12 17:06:54
7180
发布2019-11-12 17:06:54
举报
文章被收录于专栏:业余草业余草

原文链接:https://redislabs.com/

有人说 Redis 的 set 命令是一个危险命令。为什么会有这样的理解,我们一起来看看老外怎么说!

前言

Helicoprion(旋齿鲨)是一种现已灭绝但奇怪的动物,它生活在二叠纪早期的海洋中,它在尺寸和形状上与现代大白鲨看起来或多或少相似,它曾经是海洋中强大的掠夺者,因其下颌上长着排列成螺旋状的牙齿而得名,这有点类似于在下颚内部放置一个带有鲨鱼齿的圆锯,但这不符合生物的进化论,因此我们现在看不到这样的物种了。

在某些方面,Redis SET 命令就像旋齿鲨,但它仍然在全球范围内的大量 Redis 服务器上被使用。SET 是一个非常早期的命令,具有一些非常有用、不寻常的功能,但是在深度使用的同时可能存在风险。

SET 命令看起来很简单直接,我们在学习 Redis 的时候通常将它用作第一个命令,我们使用它进行简单的测试以确保 Redis 正常工作。比如:

> SET foo bar

表面上没什么特别的,但它隐藏了什么吗?

SET命令:一种数据的破坏者

回到我们简单的 SET 示例。让我们模拟一个更复杂的场景:

> UNLINK foo	
(integer) 1	
> HSET foo bar 123	
(integer) 1	
> SET foo bar	
OK

有没有用 SET 发现这里的怪异?现有的键 foo 是 hash 类型(由于 HSET),但是当我之后立即运行 SET 时它仍然可以正常工作。与其他Redis命令相比,这实际上非常奇怪。让我们采取相同的命令,但对最后两个命令使用相反的顺序:

> UNLINK foo	
(integer) 1	
> SET foo bar	
OK	
> HSET foo bar 123	
(error) WRONGTYPE Operation against a key holding thewrong kind of value

您可以看到 SET 忽略键的存在或类型,并始终写入,另一方面,哈希在面对不同类型的非空键时会抛出错误。除了字符串之外的所有数据类型都是如此,特别是 SET 命令和一些衍生的命令(PSETEX,SETEX,MSET),例如:

 > HSET foo bar 123	
(integer) 1	
> APPEND foo bar	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> INCR foo	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> SETBIT foo 1 1	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> BITFIELD foo SET u8 0 1	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> INCRBY foo 1	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> INCRBYFLOAT foo 1	
(error) WRONGTYPE Operation against a key holding thewrong kind of value	
> SETRANGE foo 1 barbar	
(error) WRONGTYPE Operation against a key holding thewrong kind of value

SETNX 和 SET ... NX(稍后会详细介绍)是一个有趣的旁注,如果键不存在,它们将设置 SET,如果设置了则返回 1,否则返回 0。因此,它不会进行类型检查,而是进行状态检查。

总而言之,SET 不关心键是什么类型,它都会覆盖,很少有其他命令能够挡住它前进的道路。

一种TYPE,三种类型

如果您已经在 Redis 中遇到过几次,那么您就知道可以使用 TYPE 命令查询存储在键中的数据类型。举个例子,让我们回到 foo:

 > SET foo bar	
OK	
> TYPE foo	
string

您可以很容易地在键 foo 上设置值“bar”。现在让我们看看别的东西:

> SET foo 1234	
OK	
> TYPE foo	
String	
> GETRANGE foo 2 3	
"34"

因此,您可能会认为数字 1234 被存储为字符,这时候可以说你的想法或多或少是正确的,但是,请继续往下看:

> INCR foo	
(integer) 1235	
> GETRANGE foo 2 3	
"35"

这说明 Redis 将字符理解为文本和数字 - 您可以将其视为松散的类型, 但它很奇怪:

> SET foo "hello world"	
OK	
> INCR foo	
(error) ERR value is not an integer or out of range

显然,Redis 不能对非数字执行 INCR。但请继续看, Redis 也能理解浮点值,举个例子:

> SET foo 1.2	
OK	
> INCR foo	
(error) ERR value is not an integer or out of range	
> INCRBYFLOAT foo 0.8	
"2"	
> INCR foo	
(integer) 3

您可以看到初始值是作为 float 放入的,因此 INCR(对于整数)将不起作用,但是,INCRBYFLOAT 确实有效,这 1.2 + 0.8 = 2 会将值更改为前一个 INCR 命令允许使用的整数。

一个命令,多种参数

该命令的另一个独特之处在于能够提供两类可选参数:一类用于到期,另一类用于存在检查。我们来看看第一个类别:到期参数。

对于大多数命令,如果要立即使键过期,则需要立即发出 EXPIRE 或 PEXPIRE,最常见的是在 MULTI / EXEC 事务中。例如:

> MULTI	
OK	
> SADD baz alpha beta gamma	
QUEUED	
> EXPIRE baz 10	
QUEUED	
> EXEC	
1) (integer) 3	
2) (integer) 1

这样可以确保在 SADD 和 EXPIRE 命令之间不会有其他命令执行,在 EXEC 执行完成之后你会有一个在 10 秒之后过期的集合。但是,使用SET,您可以在没有事务的情况下达到这样的效果。

> SET foo bar EX 10	
OK

或者,您可以使用 PX 而不是 EX 参数,使得来以毫秒而不是秒为单位到期。这是一个小技巧,也可以用 SETEX 和 PSETEX 实现, 我认为这些命令在提供便利的同时会降低可读性和灵活性。

另一类参数 NX / XX 可以控制SET命令在键存在或不存在时的行为,仅当键不存在时,NX 的键才会设置值。举个例子:

> UNLINK foo	
(integer) 0	
> SET foo 1234 NX	
OK	
> GET foo	
"1234"	
> SET foo 5678 NX	
(nil)	
> GET foo	
"1234"

您可以看到第 4 个命令实际上没有做任何事情,因为键 foo 已经存在。这有很多用途:设置默认值而不覆盖现有数据,防止在用户在误操作输入时对键的以外覆盖。

与此相反的是 XX 命令,这仅在键已存在时设置值:

> UNLINK foo	
(integer) 1	
> SET foo 1234 XX	
(nil)	
> set foo 1234	
OK	
> SET foo 5678 XX	
OK

这可用于将写入限制在已经定义过的键上。一种使用这个命令的场景是输入检查,只有在已经输入的情况下,才会把 Key 覆盖。

那么SET是一种危险的、不好的、不建议使用的命令?

绝对不是这样的,SET 是 Redis 中许多优秀实践的基础,但是它同时也具有许多与 Redis 其他命令根本不同的特性,重要的是要了解这些功能和命令如何工作,在此基础之上才能更好地组织 Redis 的键空间,以及在应用程序中正确的使用 Redis。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档