Redis的优势之一在于提供了丰富的数据类型,它不仅仅支持基本的Key-Value类型数据,还提供list、set、zset和hash等数据结构的存储。Redis没有直接使用C语言传统的字符串表示方式,而是自己构建了一种名为简单动态字符串的抽象类型,并将该类型用作Redis的默认字符串表示。简单动态字符串的英文是Simple Dynamic String,缩写为SDS。视频讲解如下:
Redis使用SDS表示字符串的优势在于:
- 获取字符串的长度的事件复杂度为o(1)。
- API安全,即通过API操作sds不会造成缓冲区溢出。
- 每次修改字符串不一定需要进行内存分配,提高性能。
- 可以保存文本和二进制数据。
SDS字符串的结构声明如下:
struct sdshdr { // 记录 buf 数组中已经使用字节的数量 // 等于 SDS 所保存字符串的长度 unsigned int len; // 记录 buf 数组中还未使用字节的数量 unsigned int free; // 字节数组,数据域,保存字符数据 char buf[]; };
SDS字符串结构中的buf是一个柔性数组(Flexible Array Member),又称伸缩性数组成员,这种数组主要是为了结构体而产生的。因为开发时,偶尔需要在结构体中存放长度可变的数组,一般情况下会定义一个数组指针,在需要时分配内存使用,这样有个缺点就是,内存利用的效率很低,所以柔性数组作用就像动态数组一样,可以在结构体中存放一个长度动态的字符串。下图展示了一个使用SDS存储的字符串。
下面是在Redis中如何操作字符串。
- SET key value
设置指定key的值
# 对不存在的键进行设置 redis 127.0.0.1:6379> SET key "value" OK redis 127.0.0.1:6379> GET key "value" # 对已存在的键进行设置 redis 127.0.0.1:6379> SET key "new-value" OK redis 127.0.0.1:6379> GET key "new-value"
- GET key
获取指定key的值
# 对不存在的 key 或字符串类型 key 进行 GET redis> GET db (nil) redis> SET db redis OK redis> GET db "redis" # 对不是字符串类型的 key 进行 GET redis> DEL db (integer) 1 redis> LPUSH db redis mongodb mysql (integer) 3 redis> GET db (error) ERR Operation against a key holding the wrong kind of value
- GETRANGE key start end
返回 key 中字符串值的子字符
redis> SET mykey "This is my test key" OK redis> GETRANGE mykey 0 3 "This" redis> GETRANGE mykey 0 -1 "This is my test key"
- GETSET key value
将给定key的值设为value ,并返回key的旧值(old value)
redis> DEL db (integer) 1 redis> GETSET db mongodb # 没有旧值,返回 nil (nil) redis> GET db "mongodb" redis> GETSET db redis # 返回旧值 mongodb "mongodb" redis> GET db "redis"
- MGET key1 [key2..]
获取所有(一个或多个)给定key的值
redis> SET key1 "hello" OK redis> SET key2 "world" OK redis> MGET key1 key2 someOtherKey 1) "Hello" 2) "World" 3) (nil)
- SETEX key seconds value
将值value关联到key ,并将key的过期时间设为seconds(以秒为单位)
redis> SETEX mykey 10 redis OK redis> TTL mykey 10 redis> GET mykey "redis
- SETNX key value
只有在key不存在时设置 key 的值
redis> EXISTS job # job 不存在 (integer) 0 redis> SETNX job "programmer" # job 设置成功 (integer) 1 redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败 (integer) 0 redis> GET job # 没有被覆盖 "programmer"
- SETRANGE key offset value
用value参数覆写给定key所储存的字符串值,从偏移量offset开始
redis> SET key1 "Hello World" OK redis> SETRANGE key1 6 "Redis" (integer) 11 redis> GET key1 "Hello Redis"
- STRLEN key
返回key所储存的字符串值的长度
# 获取字符串的长度 redis> SET mykey "Hello world" OK redis> STRLEN mykey (integer) 11 # 不存在的 key 长度为 0 redis> STRLEN nonexisting (integer) 0
- MSET key value [key value ...]
同时设置一个或多个key-value对
redis> MSET key1 "Hello" key2 "World" OK redis> GET key1 "Hello" redis> GET key2 1) "World"
- MSETNX key value [key value ...]
同时设置一个或多个key-value对,当且仅当所有给定key都不存在
# 对不存在的 key 进行 MSETNX redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis" (integer) 1 redis> MGET rmdbs nosql key-value-store 1) "MySQL" 2) "MongoDB" 3) "redis" # MSET 的给定 key 当中有已存在的 key redis> MSETNX rmdbs "Sqlite" language "python" (integer) 0 # rmdbs键已经存在,操作失败 redis> EXISTS language # 因为MSET是原子性操作,language没有被设置 (integer) 0 redis> GET rmdbs # rmdbs也没有被修改 "MySQL"
- PSETEX key milliseconds value
这个命令和SETEX命令相似,但它以毫秒为单位设置key的生存时间,而不是像SETEX命令那样,以秒为单位
redis> PSETEX mykey 1000 "Hello" OK redis> PTTL mykey 999 redis> GET mykey 1) "Hello"
- APPEND key value
如果key已经存在并且是一个字符串,APPEND命令将指定的value追加到该key原来值(value)的末尾
# 对不存在的 key 执行 APPEND redis> EXISTS myphone # 确保myphone不存在 (integer) 0 redis> APPEND myphone "nokia" # 对不存在的key进行APPEND ,等同于SET myphone "nokia" (integer) 5 # 字符长度 # 对已存在的字符串进行 APPEND redis> APPEND myphone " - 1110" # 长度从5个字符增加到12个字符 (integer) 12 redis> GET myphone "nokia - 1110"