专栏首页业余草为什么有人说 Redis 的 set 命令是一个危险命令?

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

原文链接: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。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • jqm视频播放器,html5视频播放器,html5音乐播放器,html5播放器,video开发demo,html5视频播放示例,html5手机视频播放器

    最近在论坛中看到了很多实用html5开发视频播放,音乐播放的功能,大部分都在寻找答案。因此我就在这里做一个demo,供大家相互...

    业余草
  • 网络 IO 模型:同步异步,傻傻分不清楚?

    阻塞 IO, 非阻塞 IO, 同步 IO, 异步 IO 这些术语相信有不少朋友都也不同程度的困惑吧? 我原来也是, 什么同步非阻塞 IO, 异步非阻塞 IO 的...

    业余草
  • 手把手教你使用 Java 和 Redis 实现排行榜!

    编辑:业余草 来源:https://www.xttblog.com/?p=4937

    业余草
  • 独家 | 一文了解强化学习的商业应用2

    作者:Aishwarya Srinivasan, Deep Learning Researcher

    数据派THU
  • 大咖 | 专访Yoshua Bengio:如何高效建立和运营一家机器学习实验室?

    人工智能和机器学习风靡全球,高校作为人才培养基地正在顶风而上,如何建立相关的实验室,“当家人”如何管理实验室才能最高效?关于这些问题,无论国内,还是国外的学者都...

    大数据文摘
  • 三步理解--门控循环单元(GRU),TensorFlow实现。

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    mantch
  • 【综述】​从基础到前沿看迁移学习在NLP中的演化

    论文标题:Evolution of Transfer Learning in Natural Language Processing

    yuquanle
  • ​迁移学习在NLP中的演化:从基础到前沿

    论文标题:Evolution of Transfer Learning in Natural Language Processing

    AI科技评论
  • 速读原著-TCP/IP(sock程序)

    在本书中一直使用一个称为 s o c k的小测试程序,用来生成 T C P和U D P数据。它既可以用作一个客户进程,也可以用作一个服务器进程。有这样一个可以从...

    cwl_java
  • PostgreSql 复杂的查询,我可怎么分析 (神奇的web site)

    永久了MYSQL 可能会忘记什么是复杂的查询,每种数据库有自己的特点,POSTGRESQL 是一个 OLAP + OLTP 兼得的数据库,所以postgresq...

    AustinDatabases

扫码关注云+社区

领取腾讯云代金券