string类型常用命令与其底层数据结构

125 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

string类型命令

set

格式:SET key value [EX seconds | PX milliseconds] [NX|XX]

功能:SET 除了可以直接将 key 的值设为 value 外,还可以指定一些参数。

  • EX seconds:为当前 key 设置过期时间,单位秒。等价于 SETEX 命令。
  • PX milliseconds:为当前 key 设置过期时间,单位毫秒。等价于 PSETEX 命令。
  • NX:指定的 key 不存在才会设置成功,用于添加指定的 key。等价于 SETNX 命令。
  • XX:指定的 key 必须存在才会设置成功,用于更新指定 key 的 value。

说明:如果 value 字符串中带有空格,则该字符串需要使用双引号或单引号引起来,否则会认为 set 命令的参数数量不正确,报错。

setex与psetex

格式:SETEX/PSETEX key seconds value

功能:set expire,其不仅为 key 指定了 value,还为其设置了生存时间。setex 的单位为秒,psetex 的单位为毫秒。

说明:如果 key 已经存在, 则覆写旧值。该命令类似于以下两个命令,不同之处是,SETEX 是一个原子性操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在 Redis 用作缓存时,非常实用。

SET key value

EXPIRE key seconds # 设置生存时间

setnx

格式:SETNX key value

功能:SET if Not eXists,将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key已经存在,则 SETNX 不做任何动作。成功,返回 1,否则,返回 0。

说明:该命令等价于 set key value nx

getset

格式:GETSET key value

功能:将给定 key 的值设为 value ,并返回 key 的旧值。

说明:当 key 存在但不是字符串类型时,返回一个错误;当 key 不存在时,返回 nil 。

mset与 msetnx

格式:MSET/MSETNX key value [key value ...]

功能:同时设置一个或多个 key-value 对。

说明:如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。MSET/MSETNX 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况不可能发生。该命令永不失败。

mget

格式:MGET key [key ...]

功能:返回所有(一个或多个)给定 key 的值。

说明:如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败

append

格式:APPEND key value

功能:如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。

说明:追加 value 之后, key 中字符串的长度。

注意:如果要追加的字符串中有空格需要加上双引号或者单引号

incr与decr

格式:INCR key 或 DECR key

功能:

  • increment,自动递增。将 key 中存储的数字值增一。
  • decrement,自动递减。将 key 中存储的数字值减一。

说明:如果 key 不存在,那么 key 的值会先被初始化为 0,然后再执行增一/减一操作。如果值不能表示为数字,那么返回一个错误提示。如果执行正确,则返回增一/减一后的值

incrby与decrby

格式:INCRBY key increment 或 DECRBY key decrement

功能:将 key 中存储的数字值增加/减少指定的数值,这个数值只能是整数,可以是负数,但不能是小数。

说明:如果 key 不存在,那么 key 的值会先被初始化为 0,然后再执行增/减操作。如果值不能表示为数字,那么返回一个错误提示。如果执行正确,则返回增/减后的值。

incrbyfloat

格式:INCRBYFLOAT key increment

功能:为 key 中所储存的值加上浮点数增量 increment 。

说明:与之前的说明相同。没有 decrbyfloat 命令,但 increment 为负数可以实现减操作效果。

strlen

格式:STRLEN key

功能:返回 key 所储存的字符串值的长度。

说明:当 key 储存的不是字符串值时,返回一个错误;当 key 不存在时,返回 0 。

getrange

格式:GETRANGE key start end

功能:返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定,包括 start 和 end 在内。

说明:end 必须要比 start 大。支持负数偏移量,表示从字符串最后开始计数,-1 表示最后一个字符,-2 表示倒数第二个,以此类推。

setrange

格式:SETRANGE key offset value

功能:用 value 参数替换给定 key 所储存的字符串值 str,从偏移量 offset 开始。

说明:当 offset 值大于 str 长度时,中间使用零字节\x00 填充,即 0000 0000 字节填充;对于不存在的 key 当作空串处理。

SDS(Simple Dynamic String)

定义在 Redis 安装目录下的 src/sds.h 中,SDS结构体:

struct sdshdr {

// 字节数组,用于保存字符串

char buf[];

// buf[]中已使用字节数量,称为 SDS 的长度

int len;

// buf[]中尚未使用的字节数量

int free;

}

注意:SDS 的 len 是不包含空字符’\0’的。

SDS 的优势:

防止”字符串长度获取”性能瓶颈

​ 对于 C 字符串,若要获取其长度(strlen),则必须要通过遍历整个字符串才可获取到的。对于超长字符串的遍历,会成为系统的性能瓶颈。

保障二进制安全

  SDS 不是以空字符’\0’作为字符串结束标志的,其是通过 len 属性来判断字符串是否结束的。图片、音频、视频、压缩文件、office 文件等二进制数据中以空字符’\0’作为分隔符的情况是很常见的。故而在 C 字符串中是不能保存像图片、音频、视频、压缩文件、office 文件等二进制数据的。

减少内存再分配次数

  SDS 采用了空间预分配策略与惰性空间释放策略来避免内存再分配问题。

  空间预分配策略是指,每次 SDS 进行空间扩展时,程序不但为其分配所需的空间,还会为其分配额外的未使用空间,以减少内存再分配次数。而额外分配的未使用空间大小取决于空间扩展后 SDS 的 len 属性值。

  • 如果 len 属性值小于 1M,那么分配的未使用空间 free 的大小与 len 属性值相同。(注意len不包含'\0')

  • 如果 len 属性值大于等于 1M ,那么分配的未使用空间 free 的大小固定是 1M。

​ 惰性空间释放策略是指,SDS 字符串长度如果缩短,那么多出的未使用空间将暂时不释放,而是增加到 free 中。以使后期扩展 SDS 时减少内存再分配次数。如果要释放 SDS 的未使用空间,则可通过 **sdsRemoveFreeSpace()**函数来释放。

兼容C函数

​ Redis 中提供了很多的 SDS 的 API,以方便用户对 Redis 进行二次开发。为了能够兼容 C函数,SDS 的底层数组 buf[]中的字符串仍以空字符’\0’结尾。 例如:strcmp(sds_str->buf,c_str)

sdsnew()

使用指定的 C 字符串创建一个 SDS

sdsempty()

创建一个不包含任何字符串数据的 SDS

sdsdup()

创建一个指定 SDS 的副本

sdsfree()

释放指定的 SDS

sdsclear()

清空指定 SDS 的字符串内容

sdslen()

获取指定 SDS 的已使用空间 len 值

sdsavail()

获取指定 SDS 的未使用空间 free 值

sdsMakeRoomFor()

使指定的 SDS 的 free 空间增加指定的大小

sdsRemoveFreeSpace() 释放指定 SDS 的 free 空间

sdscat()

将指定的 C 字符串拼接到指定 SDS 字符串末尾

sdscatsds()

将指定的 SDS 的字符串拼接到另一个指定 SDS 字符串末尾

sdscpy()

将指定的 C 字符串复制到指定的 SDS 中,覆盖原 SDS 字符串内容

sdsgrouzero()

扩展 SDS 字符串到指定长度。这个扩展是使用空字符’\0’填充

sdsrange()

截取指定 SDS 中指定范围内的字符串

sdstrim()

在指定 SDS 中删除所有指定 C 字符串中出现的所有字符

sdsemp()

对比两个给定的 SDS 字符串是否相同

sdstolow()

将指定 SDS 字符串中的所有字母变为小写

sdstoupper()

将指定 SDS 字符串中的所有字母变为大写