文章目录
- 前言
- 常见命令
- SET
- GET
- MSET
- MGET
- INCR
- INCRBY
- DECR
- DECRBY
- INCRBYFLOAT
- APPEND
- GETRANGE
- SETRANGE
- STRLEN
- 命令小结
前言
Redis 的数据有很多种数据类型,包括字符串类型、列表类型、哈希类型、集合类型、有序集合类型等。这几种数据类型是针对于 value 来说的,redis 的 key 都是字符串类型,可以说字符串是 redis 最基本的数据类型,其他几种数据结构也是在字符串类似基础上构建的,例如列表和集合的元素类型是字符串类型,所以字符串类型能为其他 4 种数据结构的学习奠定基础。
字符串类型的值实际可以是字符串,包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,例如图⽚、⾳频、视频等。不过⼀个字符串的最⼤值不能超过 512 MB。
字符串数据类型
常见命令
SET
set 命令将 String 类型的 value 设置到 key 中。如果之前 key 存在,则覆盖,无论之前的数据类型是什么,都会将其覆盖,并且关于之前 key 的 TTL 全部失效。
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 的完整用法如下:
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,在工作中一定要慎用该命令。
//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)
//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
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
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 的简单用法。
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
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 值加一之后的值
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 之后的结果
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 也可以为负数:
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 之后的值
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 之后的值
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 也可以是负数:
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 之后的值
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 的长度(单位字节)
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 会尽可能的对二进制数据进行翻译。
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 类型的子串
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 获得的子串可能就不是完整的汉字了:
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为子串的长度
返回值:替换后的字符换的长度
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 设置的返回不是完整的一个汉字的时候,就可能出现其他的汉字。
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
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) |