前言:
在《Redis 第五讲 --- 数据类型篇 数据类型与内部编码》中,我们深入探讨了Redis核心数据类型的分类及其底层编码机制,理解了不同场景下数据结构的选择逻辑。今天,我们进入《Redis 第六讲 --- 数据类型篇 string指令》,聚焦最基础且强大的string类型。
string类型不仅是Redis的基石,还因其灵活性支持丰富操作:从简单的键值存储(set
/get
)到复杂功能(原子计数incr
、过期管理ex
、条件设置nx
)。本讲将系统解析string指令的核心细节:
存储优势:二进制安全设计,大幅降低乱码风险;
高效操作:
mset
/mget
批量处理(O(N))、append
拼接、getrange
子串截取;数值运算:
incrby
对整数原子增减(O(1)),注意浮点数与大数的限制;汉字处理:以字节存储的注意事项,避免错误切分;
实战技巧:
flushall
风险预警、set key value ex
过期控制、setnx
分布式锁实现等。
通过本讲,外面将掌握主要string指令的妙用,为高性能开发铺平道路。
目录
一、string的类型介绍
字符串类型是 Redis 最基础的数据类型,关于字符串需要特别注意:
1)⾸先 Redis 中所有的键的 类型都是字符串类型,⽽且其他⼏种数据结构也都是在字符串类似基础上构建的,例如列表和集合的 元素类型是字符串类型,所以字符串类型能为其他 4 种数据结构的学习奠定基础。
2)其次,字符串类型的值实际可以是字符串,包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,例如图⽚、⾳频、视频等。不过⼀个字符 串的最⼤值不能超过 512 MB。
注意:由于 Redis 内部存储字符串完全是按照⼆进制流的形式保存的,所以 Redis 是不处理字符集 编码问题的,客⼾端传⼊的命令中使⽤的是什么字符集编码,就存储什么字符集编码。
所以Redis的使用不像MySQL那样容易出现乱码问题。
在MySQL当中,我们的存储与查询的字符集不同的时候,会出现乱码问题,最典型就是关于汉字的存储,但是在Redis这里不一样,Redis统一存储成二进制,查询的结果以十六进制显示。如下
我们借助网上的一些转进制工具查看一下结果,
注意:“\x”是表示后面的符号是十六进制的意思。
如果我们想要让Redis直接进行内部编码转化,直接指令后带选项 --raw。【注意:这里的指令是要求在启动redis客户端的时候带上的。】
现在我们已经对string类型有了初步的介绍,我们下面看一下string类型的指令吧。
二、set与get
这两个指令其实在string这里有我们前面学习到的全局指令没啥不同,我们直接来看一下使用。
2.1 set
将 string 类型的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么。之 前关于此 key 的 TTL 也全部失效。
时间复杂度:O(1)
选项:
SET 命令⽀持多种选项来影响它的⾏为:
• EX seconds⸺使⽤秒作为单位设置 key 的过期时间。
• PX milliseconds⸺使⽤毫秒作为单位设置 key 的过期时间。
• NX ⸺只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。
• XX ⸺只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。
针对set的一些常见用法,进行了缩写;之所以这样搞,就是为了让操作更符合人的直觉.(使用者的门槛就越低,要背的东西就越少)
那这些选项什么意思呢?
就是说这个set指令可以一次执行多条指令的效果,像之前的expire指令,功能就被做成一个选项了,降低了客户端与服务端的网络通信次数,减少消耗。
例如:set key value ex 10 相当于 set key value + expire key 10。
注意:由于带选项的 SET 命令可以被 SETNX 、 SETEX 、 PSETEX 等命令代替,所以之后的版本 中,Redis 可能进⾏合并。
返回值:
• 如果设置成功,返回 OK。
• 如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回 (nil)。
还有一点,就是关于Redis文档查询的问题。
当我们看到一条指令发现这样的格式:
格式说明:[]相当于一个独立的单元,表示可选项(可有可无的),其中|表示”或者”的意思,多个只能出现一个。[]和[]之间,是可以同时存在的.
话不多说,我们直接演示一下吧!
演示:
1)set的覆盖效果
2)set的选项演示
我们成功的将两条指令结合成一条指令。
当key已经存在的时候,NX就无法继续设置了。
2.2 get
获取 key 对应的 value。如果 key 不存在,返回 nil。如果 value 的数据类型不是 string,会报错。 语法:
1 GET key
时间复杂度:O(1)
返回值:key 对应的 value,或者 nil 当 key 不存在。
演示:
但是可以会有小伙伴问,Redis 的mset指令可以一次设置多个key,那么get可以获得多个value吗?
答案是不可以的!下面我们来演示一下。
但是我们Redis还有对应的同时对多个key进行操作的指令,只需要在前面加上m就好了。
使⽤ mget / mset 由于可以有效地减少了⽹络时间,所以性能相较更⾼。如果以后存在大量的key设置与获取我们可以考虑使用mset与mget。
2.3 flushall
在告诉大家一个闯祸小技巧 --- 指令 flushall
FLUSHALL可以把redis上所有的键值对都带走,以后在公司,尤其是生产环境的数据库,千万千万不敢敲!!
例如我们上面演示指令产生了许多的没有的指令,现在我们是学习阶段可以人为的删除一下。
演示:
注意:对于GET来说,只是支持,字符串类型的value,如果value是其他类型,使用GET获取就会出错!!关于如何获取其他类型的指令那就是我们后面学习的内容了。
三、incr与decr系列
这个系列的函数其实针对value为数字的字符串进行操作的。它们可以对value进行加减等操作。
- incr:针对 value + 1
- incrby:针对 value + n
- decr:针对 value -1
- decrby:针对 value - n
- incrbyfloat:针对 value +/- 小数
但是使用也是存在限制的,比如我们操作的value值太大了,超过了8个字节能表示的最大数值,或者是这个key根本不存在但是这种情况比较特殊,上述指令会把这个key的value当成0开始操作。
特殊的存在::incrbyfloat
把 key 对应的 value 进行+ - 运算.,运算的操作数可以是浮点数。
虽然此处没有提供减法版本的命令,但是使用redis进行的计数操作,一般都是针对整数来进行的, 能用加上负数的形式来实现减法。
为啥说这个指令特殊呢?
因为这个指令不想上面的其他四个指令,它们都有对应的相反操作的指令。
废话不说,直接开始演示。
演示:
1)incr 与incrby
这几个指令在使用完成后,都是会打印出操作结果的。
2)decr 与 decrby
在进行减法操作的时候,直接减去负数也是可以达到加法的效果的。
3)incrbyfloat
上面的几个指令是无法对浮点数进行操作的,只有incrbyfloat可以操作。
注:上述操作的时间复杂度,都是0(1),由于redis处理命令的时候,是单线程模型.多个客户端同时针对同一个key进行incr操作,不会引起"线程安全”问题。
四、append与getrange
毕竟我们的string类型主要是针对字符串进行操作的,所以我们怎么能少了对字符串操作的指令呢?
字符串也有一些指令支持一些常用的操作.拼接,获取/修改字符串的部分内容,获取字符串长度,
我们下面来介绍一下。
4.1 APPEND
如果 key 已经存在并且是⼀个 string,命令会将 value 追加到原有 string 的后边。如果 key 不存在, 则效果等同于 SET 命令。
语法:
1 APPEND KEY VALUE
时间复杂度:O(1). 追加的字符串⼀般⻓度较短, 可以视为 O(1)
.返回值:追加完成之后 string 的⻓度,长度的单位是字节!!
注意:redis的字符串,不会对字符编码做任何处理.(redis不认识字符,只认识字节)
演示:
我们当前的xshell终端,默认的字符编码是utf8.,在终端中输入汉字之后,也就是按照utf8编码的
而一个汉字在utf8字符集中,通常是3个字节的;在gbk编码当中则是占据2个字节。
4.2 GETRANGE
返回 key 对应的 string 的⼦串,由 start 和 end 确定(左闭右闭)。
编程这个大圈子中,区间大多是前闭后开,但是确实有特殊情况,比如Redis但是这个跟别的设计脱节还是不好的。但是不同之处还没完,正常下标都是从0开始的整数,redis的下标是可以支持负数的,还好开头还是从0开始的。
语法:
1 GETRANGE key start end
可以使⽤负数表⽰倒数。
-1 代表 倒数第⼀个字符,-2 代表倒数第⼆个,其他的与此类似。超过范围的偏移量会根据 string 的⻓度调整 成正确的值。
时间复杂度:O(N). N 为 [start, end] 区间的⻓度. 由于 string 通常⽐较短, 可以视为是 O(1)
返回值:string 类型的⼦串
演示:
1)英文
2)中文
这里我启动redis客户端的时候带上了 --raw选项,所以现在还是截取比较好的。
但是如果不是raw模式呢?
这样的截取使用的是字节为单位,所以会截出一些没有意义的乱码。
所以字符串中保存的是汉字,此时进行子串切分,很可能切出来的就不是完整的汉字了
上述的代码,是强行切出了中间的四个字节,随便这么一切,切出的结果在utf8码表上不知道能查出啥了。
五、setrange与strlen
5.1 setrange
覆盖字符串的⼀部分,从指定的偏移开始。
语法:
1 SETRANGE key offset value
时间复杂度:O(N), N 为 value 的⻓度. 由于⼀般给的 value ⽐较短, 通常视为 O(1).
返回值:替换后的 string 的⻓度。
演示:
1)英文
2)中文
这个key对应的value是“张三与李四”
如果当前咱们value是一个中文字符串.进行setrange的时候,是可能会搞出问题的!!
3)对于不存在的key操作呢?
我们发现一样是可以操作的,不过字符串前面新增了几个0.
结论;setrange针对不存在的key也是可以操作的.不过会把offset之前的内容填充成0x00。
5.2 strlen
strlen获取到字符串的长度.(单位是字节),其他的没啥好说的,基本上与C语言的函数没啥区别。
获取 key 对应的 string 的⻓度。当 key 存放的类似不是 string 时,报错。
语法:
1 STRLEN key
时间复杂度:O(1)
返回值:string 的⻓度。或者当 key 不存在时,返回 0。
注:单位是字节。
演示:
总结:
至此,我们完成了string指令的全面解析:从基础存取、过期管理到原子运算与字符串操作,您已掌握如何高效利用Redis处理文本、数值及二进制数据。特别注意汉字存储以字节为单位的特性,避免子串截取时的乱码问题;同时善用setnx
、incrby
等原子操作,可大幅简化分布式逻辑。
在下一讲《Redis 第七讲 --- 数据类型篇 string的内部编码》中,我们将深入string的底层实现:揭秘int、embstr、raw三种编码的动态转换机制,分析内存优化策略与性能取舍。理解内部编码,才能真正发挥Redis极致性能。
我们下期见!