Redis(三) String字符串

文章目录

前言

Redis 的数据有很多种数据类型,包括字符串类型、列表类型、哈希类型、集合类型、有序集合类型等。这几种数据类型是针对于 value 来说的,redis 的 key 都是字符串类型,可以说字符串是 redis 最基本的数据类型,其他几种数据结构也是在字符串类似基础上构建的,例如列表和集合的元素类型是字符串类型,所以字符串类型能为其他 4 种数据结构的学习奠定基础。

字符串类型的值实际可以是字符串,包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,例如图⽚、⾳频、视频等。不过⼀个字符串的最⼤值不能超过 512 MB。

字符串数据类型

常见命令

SET

set 命令将 String 类型的 value 设置到 key 中。如果之前 key 存在,则覆盖,无论之前的数据类型是什么,都会将其覆盖,并且关于之前 key 的 TTL 全部失效。

java 复制代码
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> expire key1 10
(integer) 1
127.0.0.1:6379> ttl key1
(integer) 6
127.0.0.1:6379> set key1 world
OK
127.0.0.1:6379> get key1
"world"
127.0.0.1:6379> ttl key1
(integer) -1

上面只是 set 的简单用法,set 的完整用法如下:

java 复制代码
SET key value [expiration EX seconds | PX milliseconds] NX | XX]
  • EX seconds:以秒为单位设置 key 的过期时间
  • PX milliseconds:以毫秒为单位设置 key 的过期时间
  • NX:只有当 key 不存在时才进行设置,key 存在设置不执行
  • XX:只有当 key 存在时才进行设置,key 不存在时设置不执行

并且 SET 命令还可以简化为:SETNX、SETEX、SETPX、SETXX、PSETNX

SET 命令时间复杂度:O(1)
返回值:设置成功返回 OK,失败返回 nil

FLUSHALL 可以用来清除当前 redis 中存储的所有 key,在工作中一定要慎用该命令。

java 复制代码
//NX key1不存在时创建
127.0.0.1:6379> set key1 hello ex 10 NX
OK
127.0.0.1:6379> ttl key1
(integer) 5
127.0.0.1:6379> ttl key1
(integer) -2
//key1存在时创建,失败
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> set key1 world ex 10 NX
(nil)
java 复制代码
//XX key1 存在时创建,成功
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> set key1 world ex 10 XX
OK
127.0.0.1:6379> get key1
"world"
127.0.0.1:6379> ttl key1
(integer) 4
//XX key1不存在时创建,失败
127.0.0.1:6379> get key1
(nil)
127.0.0.1:6379> set key1 hello ex 10 XX
(nil)

GET

获取 key 对应的 value,如果 key 不存在,则返回 nil,如果 value 的类型不为 String 字符串类型,则会报错。

GET 命令时间复杂度:O(1)
返回值:获取成功返回对应 key 的 value 值,key 不存在返回 nil

java 复制代码
127.0.0.1:6379> keys *
(empty array)
//key1不存在
127.0.0.1:6379> get key1
(nil)
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> get key1
"hello
127.0.0.1:6379> lpush key2 nihao
(integer) 1
127.0.0.1:6379> get key2
(error) WRONGTYPE Operation against a key holding the wrong kind of value

使用 lpush 命令设置的 key 的 value 的数据类型是列表类型,当我们使用 get 名来来获取 key 的时候就会报错:WRONGTYPE Operation against a key holding the wrong kind of value

MSET

mset 命令用来一次设多个 key,因为分多次设置 key 的话,就意味着需要进行多次网络传输,那么速度就会很慢,所以我们 redis 也考虑到了这点,允许一次请求设置多个 key。MSET key value [key value...]

MSET 时间复杂度:O(N),N为key的数量
返回值:设置成功返回 OK,设置失败返回 nil

java 复制代码
127.0.0.1:6379> mset key1 hello key2 world
OK
127.0.0.1:6379> get key1
"hello"
127.0.0.1:6379> get key2
"world"

但是这个一次设置多个 key 的时候就不能像上面的 set 完整命令一样了,这里一次设置多个 key 只支持 set 的简单用法。

java 复制代码
127.0.0.1:6379> mset key1 hello ex 20 NX key2 world ex 20 NX
OK
127.0.0.1:6379> ttl key1
(integer) -1
127.0.0.1:6379> get key1
"hello"
127.0.0.1:6379> get key2
(nil)

MGET

与 MSET 相对应的------MGET可以一次获取多个 key:
MGET key [key...]

MGET 时间复杂度:O(N),N为 key 的数量
返回值:获取成功,返回n个 key 对应的 value 值,获取失败,key 不存在,对应的返回值为 nil

java 复制代码
127.0.0.1:6379> mset key1 hello key2 world
OK
127.0.0.1:6379> mget key1 key2
1) "hello"
2) "world"

INCR

INCR 命令将对应的 String 字符串所表示的数字加一。如果 key 不存在,那么这个 key 会被当作 0,然后加一结果就是1,如果 key 对应的 value 类型不是整型或者加1之后超出了 64 位可以表示的范围,则报错。INCR key

时间复杂度:0(1)
返回值:返回 key 值加一之后的值

java 复制代码
127.0.0.1:6379> set key1 10
OK
127.0.0.1:6379> incr key1
(integer) 11
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> incr key2
(integer) 1
127.0.0.1:6379> get key2
"1"
127.0.0.1:6379> set key3 hello
OK
127.0.0.1:6379> incr key3
(error) ERR value is not an integer or out of range
127.0.0.1:6379> set key4 2222222222222222222222222222222222222222222
OK
127.0.0.1:6379> incr key4
(error) ERR value is not an integer or out of range

INCRBY

INCRBY 命令将指定的 key 的值加上任意值。如果 key 不存在,那么会将这个 key 当作 0 然后相加。INCRBY key n

时间复杂度:O(1)
返回值:返回 key 加上 n 之后的结果

java 复制代码
127.0.0.1:6379> set key1 10
OK
127.0.0.1:6379> incrby key1 20
(integer) 30
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> incrby key2 40
(integer) 40
127.0.0.1:6379> get key2
"40"

当然 n 也可以为负数:

java 复制代码
127.0.0.1:6379> get key1
"30"
127.0.0.1:6379> incrby key1 -40
(integer) -10

但是我们通常不这样用,因为减去对应的值有专门的命令。

DECR

DECR 命令可以将指定的 key 减去 1,如果 key 不存在,则这个 key 会被当作 0,然后减去1,但是如果减去 1 之后的数据超过了 64 位能表示的数字就会报错。DECR key

时间复杂度:O(1)
返回值:key 减去 1 之后的值

java 复制代码
127.0.0.1:6379> set key1 10
OK
127.0.0.1:6379> decr key1
(integer) 9
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> decr key2
(integer) -1
127.0.0.1:6379> get key2
"-1"
127.0.0.1:6379> set key3 hello
OK
127.0.0.1:6379> decr key3
(error) ERR value is not an integer or out of range
127.0.0.1:6379> set key4 -222222222222222222222222222222222222
OK
127.0.0.1:6379> decr key4
(error) ERR value is not an integer or out of range

DECRBY

DECRBY 命令用来将指定的 key 减去 n。如果 key 不存在,则这个 key 会被当作 0 然后减去n。DECRBY key n

时间复杂度:O(1)
返回值:对应 key 减去 n 之后的值

java 复制代码
127.0.0.1:6379> set key1 20
OK
127.0.0.1:6379> decrby key1 10
(integer) 10
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> decrby key2 10
(integer) -10
127.0.0.1:6379> get key2
"-10"

这里 n 也可以是负数:

java 复制代码
127.0.0.1:6379> get key1
"10"
127.0.0.1:6379> decrby key1 -20
(integer) 30
127.0.0.1:6379> get key1
"30"

但是不建议这样使用,加法用 INCRBY,减法用 DECRBY。

INCRBYFLOAT

INCRBYFLOAT 将 key 对应的 string 表示的浮点数加上对应的值。如果 n 为负数,则表示减去对应的值,如果 key 不存在,则 key 会当作 0,然后减去 n。如果 key 对应的不是 string,或者不是⼀个浮点数,则报错。允许采用科学计数法表示浮点数。INCRBYFLOAT key n

时间复杂度:O(1)
返回值:对应的 key 的 value 减去 n 之后的值

java 复制代码
127.0.0.1:6379> set key1 13.14
OK
127.0.0.1:6379> incrbyfloat key1 6.86
"20"
127.0.0.1:6379> incrbyfloat key1 -10
"10"

既然存在 increbyfloat 加上浮点数的操作,那么是否存在 decrbyfloat 减去浮点数的命令呢?很遗憾这里不存在,这里 increbyfloat 是够我们使用的。

这里 incr、decr 就是类似前置++或者后置++的操作,我们都知道++操作在底层是分为三个步骤的:将变量的值从内存中读取->对变量进行+1操作->将修改之后的变量再存储到硬盘中。在多线程的环境中,由于++的操作不是原子性的操作,所以有可能发生线程不安全的问题。但是在 redis 中是不会发生这种问题的,因为我们的 redis 是单线程架构,不会出现类似的线程不安全问题。

APPEND

APPEND 命令,如果 key 已存在并且是一个 String 字符串,则会将 value 追加到原 key 的 value 的后面,如果不存在,则类似 SET 命令。APPEND key value

时间复杂度:O(1)
返回值:追加完成之后 String 的长度(单位字节)

java 复制代码
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> append key1 world
(integer) 10
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> append key2 redis
(integer) 5
127.0.0.1:6379> get key2
"redis"
127.0.0.1:6379> get key1
"helloworld"
127.0.0.1:6379> append key1 你好
(integer) 16
127.0.0.1:6379> get key1
"helloworld\xe4\xbd\xa0\xe5\xa5\xbd"

如果我们的 reids 字符串出现了中文的话,是会出现乱码的,那么为什么会出现乱码呢?这是因为 redis 底层是不知道什么字符编,redis 只认识字节,redis 中存储的是数据的二进制形式,那么通过查看 append 的返回值可以知道:在这里一个汉字占三个字节,redis 不是不知道一个字符有多少个字节吗,这里为什么呢?这是因为我们这里使用的是 xshell,xshell 默认的字符编码是 utf8,utf8中一个字符是3个字节。

但是在实际生活中我们很可能会向 redis 中存储中文,那么要想存储的中文显示出来也是中文怎么做呢?我们可以在启动 redis 的时候加上 --raw 这个选项,加上这个选项了之后,redis 会尽可能的对二进制数据进行翻译。

java 复制代码
root@iZ2ze5bzkbeuwwqowjzo27Z:~# redis-cli --raw
127.0.0.1:6379> get key1
helloworld你好
127.0.0.1:6379> 

GETRANGE

GETRANGE 返回 key 对应 string 的子串,由 start 和 end 决定(左闭右闭)。可以使用负数表示倒数,-1 表示倒数第一个字符,-2 表示倒数第二个字符...(第一个字符用0表示)

时间复杂度:O(N) N为子串的长度
返回值:string 类型的子串

java 复制代码
127.0.0.1:6379> get key1
"helloworld"
127.0.0.1:6379> getrange key1 5 9
"world"
127.0.0.1:6379> getrange key1 0 -1
"helloworld"
127.0.0.1:6379> getrange key1 4 20
"oworld"

如果 start end 的范围超出了字符串的范围,redis 会根据字符串的长度调整成正确的值。

如果字符串中存储的有汉字,那么使用 GETRANGE 获得的子串可能就不是完整的汉字了:

java 复制代码
127.0.0.1:6379> getrange key1 10 11

这里没有显示出 key1 10-11 个字节的内容,因为10-12个字节才是一个完成的汉字"你",这里10-11不能显示出完整的汉字。

SETRANGE

SETRANGE 覆盖字符串的一部分,从指定的偏移开始。SETRANGE key offset value

时间复杂度:O(N) N为子串的长度
返回值:替换后的字符换的长度

java 复制代码
127.0.0.1:6379> get key1
helloworld你好
127.0.0.1:6379> setrange key1 5 hello
16
127.0.0.1:6379> get key1
hellohello你好
127.0.0.1:6379> setrange key1 5 hellohellohello
20
127.0.0.1:6379> get key1
hellohellohellohello
127.0.0.1:6379> get key2
你好
127.0.0.1:6379> setrange key2 2 hello
7
127.0.0.1:6379> get key2
伨ello

当 SETRANGE 设置的返回不是完整的一个汉字的时候,就可能出现其他的汉字。

java 复制代码
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> setrange key3 2 hello
(integer) 7
127.0.0.1:6379> get key3
"\x00\x00hello"

SETRANGE 可以设置一个不存在的 key,只不过偏移量之前的会被用 \x00 来填充。

STRLEN

STRLEN 获取 key 对应的 string 的长度(单位是字节),如果 key 的 value 的类型不是 string 类型的话,会报错。

时间复杂度:0(1)
返回值:string 字符串的长度,如果 key 不存在返回0

java 复制代码
127.0.0.1:6379> get key1
"hellohellohellohello"
127.0.0.1:6379> strlen key1
(integer) 20
127.0.0.1:6379> get key4
(nil)
127.0.0.1:6379> strlen key4
(integer) 0

命令小结

命令 执行效果 时间复杂度
set key value [key value...] 设置 key 的值是 value O(k), k 是键个数
get key get key O(1)
del key [key ...] 删除指定的 key O(k), k 是键个数
mset key value [key value...] mset key value [key value...] O(k), k 是键个数
mget key [key ...] 批量获取 key 的值 O(k), k 是键个数
incr key 指定的 key 的值 +1 O(1)
decr key 指定的 key 的值 -1 指定的 key 的值 -1
incrby key n 指定的 key 的值 +n O(1)
decrby key n 指定的 key 的值 -n O(1)
incrbyfloat key n 指定的 key 的值 +n O(1)
append key value 指定的 key 的值追加 value O(1)
strlen key 获取指定 key 的值的⻓度 O(1)
setrange key offset value 覆盖指定 key 的从 offset 开始的部分值 O(n),n 是字符串⻓度, 通常视为 O(1)
getrange key start end 获取指定 key 的从 start 到 end 的部分值 O(n),n 是字符串⻓度, 通常视为 O(1)
相关推荐
YashanDB1 小时前
【YashanDB知识库】XMLAGG方法的兼容
数据库·yashandb·崖山数据库
独行soc1 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍11基于XML的SQL注入(XML-Based SQL Injection)
数据库·安全·web安全·漏洞挖掘·sql注入·hw·xml注入
风间琉璃""2 小时前
bugkctf 渗透测试1超详细版
数据库·web安全·网络安全·渗透测试·内网·安全工具
drebander2 小时前
SQL 实战-巧用 CASE WHEN 实现条件分组与统计
大数据·数据库·sql
IvorySQL2 小时前
IvorySQL 4.0 发布:全面支持 PostgreSQL 17
数据库·postgresql·开源数据库·国产数据库·ivorysql
18号房客3 小时前
高级sql技巧进阶教程
大数据·数据库·数据仓库·sql·mysql·时序数据库·数据库架构
Dawnㅤ3 小时前
使用sql实现将一张表的某些字段数据存到另一种表里
数据库·sql
张声录13 小时前
【ETCD】【实操篇(十二)】分布式系统中的“王者之争”:基于ETCD的Leader选举实战
数据库·etcd
运维&陈同学3 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero
有态度的马甲3 小时前
一种基于etcd实践节点自动故障转移的思路
数据库·etcd