2.1 字符串 (String)


文档摘要

2.1 字符串 (String) Redis 数据类型详解:字符串 (String) Redis 作为一种高性能的键值对存储数据库,以其丰富的数据类型和强大的功能在现代应用开发中占据着举足轻重的地位。理解 Redis 的数据类型是掌握 Redis 的基础,也是高效利用 Redis 解决实际问题的关键。 2.1 字符串 (String) 在 Redis 中,字符串 (String) 类型是最简单的数据类型。它存储的是二进制安全的数据,这意味着 Redis 字符串可以存储任何形式的数据,包括文本、数字、图片、音频、甚至序列化的对象。Redis 的字符串类型不仅仅是简单的字符串,它在底层实现上做了很多优化,使其能够高效地处理各种字符串操作。 2.1.

2.1 字符串 (String)

Redis 数据类型详解:字符串 (String)

Redis 作为一种高性能的键值对存储数据库,以其丰富的数据类型和强大的功能在现代应用开发中占据着举足轻重的地位。理解 Redis 的数据类型是掌握 Redis 的基础,也是高效利用 Redis 解决实际问题的关键。

2.1 字符串 (String)

在 Redis 中,字符串 (String) 类型是最简单的数据类型。它存储的是二进制安全的数据,这意味着 Redis 字符串可以存储任何形式的数据,包括文本、数字、图片、音频、甚至序列化的对象。Redis 的字符串类型不仅仅是简单的字符串,它在底层实现上做了很多优化,使其能够高效地处理各种字符串操作。

2.1.1 字符串的内部实现

虽然我们从概念上理解 Redis 字符串是简单的字符串,但其内部实现却并非如此简单。Redis 字符串的底层实现是简单动态字符串 (SDS, Simple Dynamic String)。SDS 相较于传统的 C 字符串,具有以下优势:

  • 二进制安全: SDS 使用 len 属性记录字符串的长度,而不是像 C 字符串那样依赖空字符 \0 来判断字符串结尾。因此,SDS 可以存储包含空字符的二进制数据,而不会被截断。

  • 杜绝缓冲区溢出: SDS 在修改字符串时,会先检查空间是否足够,如果空间不足,会自动进行空间扩展,避免缓冲区溢出。

  • 减少内存重分配次数: SDS 采用了空间预分配惰性空间释放策略,减少了字符串增长和缩短时内存重分配的次数,提高了性能。

    • 空间预分配: 当 SDS 字符串长度小于 1MB 时,每次扩展空间都会分配与 len 属性值相同的未使用空间(free 属性)。例如,如果 len 变为 10 字节,free 也会变为 10 字节,总分配空间为 20 字节。如果 len 大于等于 1MB,每次扩展空间都会额外分配 1MB 的未使用空间。

    • 惰性空间释放: 当 SDS 字符串缩短时,并不会立即释放多余的空间,而是将这些空间记录在 free 属性中,以便将来使用。如果需要真正释放空间,可以使用 sdstrim 函数。

  • 获取字符串长度的时间复杂度为 O(1): SDS 使用 len 属性直接记录字符串长度,获取长度的时间复杂度为 O(1),而 C 字符串需要遍历整个字符串才能计算长度,时间复杂度为 O(N)。

2.1.2 字符串的基本操作命令

Redis 提供了丰富的命令来操作字符串。以下是一些最常用的基本操作命令,并附带代码示例和详细解释:

1. SET 命令:设置字符串键值对

SET key value [EX seconds] [PX milliseconds] [NX|XX] [KEEPTTL]

  • 作用: 将字符串 value 关联到 key。如果 key 已经存在,则覆盖旧值。

  • 选项:

    • EX seconds: 设置键的过期时间,单位为秒。

    • PX milliseconds: 设置键的过期时间,单位为毫秒。

    • NX: Not eXists,只有当 key 不存在时才设置值。

    • XX: eXists,只有当 key 存在时才设置值。

    • KEEPTTL: 保留键的生存时间。如果键已经设置了过期时间,使用 KEEPTTL 选项后,新的值会保持原有的过期时间。

  • 返回值: 设置成功返回 OK,如果使用了 NXXX 选项但条件不满足,则返回 nil

代码示例:

redis-cli> SET mykey "Hello Redis" // 设置键 mykey 的值为 "Hello Redis" OK redis-cli> GET mykey // 获取键 mykey 的值 "Hello Redis" redis-cli> SET mykey "New Value" // 覆盖已存在的键 mykey 的值 OK redis-cli> GET mykey "New Value" redis-cli> SET anotherkey "Value with EX" EX 10 // 设置键 anotherkey 的值为 "Value with EX",过期时间为 10 秒 OK redis-cli> TTL anotherkey // 查看键 anotherkey 的剩余生存时间 (integer) 9 redis-cli> SET only_if_not_exists "New Key" NX // 使用 NX 选项,键 only_if_not_exists 不存在,设置成功 OK redis-cli> GET only_if_not_exists "New Key" redis-cli> SET only_if_not_exists "Attempt to overwrite" NX // 再次使用 NX 选项,键 only_if_not_exists 已存在,设置失败 (nil) redis-cli> GET only_if_not_exists // 值保持不变 "New Key" redis-cli> SET only_if_exists "Initial Value" // 设置键 only_if_exists 的初始值 OK redis-cli> SET only_if_exists "Overwrite existing key" XX // 使用 XX 选项,键 only_if_exists 存在,设置成功 OK redis-cli> GET only_if_exists "Overwrite existing key"

2. GET 命令:获取字符串键的值

GET key

  • 作用: 获取与 key 关联的字符串值。

  • 返回值: 如果 key 存在,则返回关联的字符串值。如果 key 不存在,则返回 nil

代码示例:

redis-cli> SET getkey "Value to get" OK redis-cli> GET getkey // 获取键 getkey 的值 "Value to get" redis-cli> GET non_existent_key // 获取不存在的键 (nil)

3. DEL 命令:删除键

DEL key [key ...]

  • 作用: 删除一个或多个指定的键。

  • 返回值: 返回成功删除的键的数量。

代码示例:

redis-cli> SET delkey "Value to delete" OK redis-cli> EXISTS delkey // 检查键 delkey 是否存在 (integer) 1 redis-cli> DEL delkey // 删除键 delkey (integer) 1 redis-cli> EXISTS delkey // 再次检查键 delkey 是否存在 (integer) 0 redis-cli> DEL key1 key2 key3 // 删除多个键 (integer) 0 // 假设 key1, key2, key3 都不存在,返回 0

4. EXISTS 命令:检查键是否存在

EXISTS key [key ...]

  • 作用: 检查一个或多个键是否存在。

  • 返回值: 返回存在的键的数量。

代码示例:

redis-cli> SET existkey "Key to check" OK redis-cli> EXISTS existkey // 检查键 existkey 是否存在 (integer) 1 redis-cli> EXISTS non_existent_key // 检查不存在的键 (integer) 0 redis-cli> EXISTS existkey non_existent_key another_exist_key // 检查多个键 (integer) 2 // 假设 existkey 和 another_exist_key 存在,返回 2

5. TTL 命令:获取键的剩余生存时间

TTL key

  • 作用: 获取键的剩余生存时间,单位为秒。

  • 返回值:

    • key 存在且设置了过期时间时,返回剩余生存时间(秒)。

    • key 存在但没有设置过期时间时,返回 -1 (永久有效)。

    • key 不存在时,返回 -2

代码示例:

redis-cli> SET ttlkey "Key with TTL" EX 30 // 设置键 ttlkey 的过期时间为 30 秒 OK redis-cli> TTL ttlkey // 获取剩余生存时间 (integer) 29 // 结果会随着时间推移而减少 redis-cli> SET persistentkey "Persistent Key" // 设置一个没有过期时间的键 OK redis-cli> TTL persistentkey // 获取没有过期时间的键的 TTL (integer) -1 redis-cli> TTL non_existent_key // 获取不存在的键的 TTL (integer) -2

6. EXPIRE 命令:设置键的过期时间

EXPIRE key seconds [NX|XX|GT|LT]

  • 作用: 为键设置过期时间,单位为秒。

  • 选项:

    • NX: 只有当键 没有 过期时间时,才设置过期时间。

    • XX: 只有当键 已经 设置了过期时间时,才更新过期时间。

    • GT: 只有当新的过期时间 大于 当前过期时间时,才更新过期时间。

    • LT: 只有当新的过期时间 小于 当前过期时间时,才更新过期时间。

  • 返回值: 设置成功返回 1,设置失败返回 0

代码示例:

redis-cli> SET expirekey "Key to expire" OK redis-cli> EXPIRE expirekey 60 // 设置键 expirekey 的过期时间为 60 秒 (integer) 1 redis-cli> TTL expirekey (integer) 59 redis-cli> EXPIRE expirekey 120 XX // 使用 XX 选项,键 expirekey 已经有过期时间,更新成功 (integer) 1 redis-cli> TTL expirekey (integer) 119 redis-cli> EXPIRE expirekey 300 GT // 使用 GT 选项,新的过期时间 300 大于当前过期时间 119,更新成功 (integer) 1 redis-cli> TTL expirekey (integer) 299 redis-cli> EXPIRE expirekey 50 LT // 使用 LT 选项,新的过期时间 50 小于当前过期时间 299,更新失败 (integer) 0 redis-cli> TTL expirekey // 过期时间保持不变 (integer) 298 redis-cli> EXPIRE persistentkey 60 NX // 使用 NX 选项,键 persistentkey 没有过期时间,设置成功 (integer) 1 redis-cli> TTL persistentkey (integer) 59 redis-cli> EXPIRE persistentkey 120 NX // 再次使用 NX 选项,键 persistentkey 已经有过期时间,设置失败 (integer) 0 redis-cli> TTL persistentkey // 过期时间保持不变 (integer) 58

2.1.3 字符串的数值操作命令

Redis 字符串可以存储数字,并提供了一些原子性的数值操作命令,非常适合用于计数器、限流等场景。

1. INCR 命令:将键的值原子性地递增 1

INCR key

  • 作用: 将键存储的值加上 1。如果键不存在,则先将键的值初始化为 0,再执行递增操作。如果键的值不是整数类型,则会返回错误。

  • 返回值: 递增后的值。

代码示例:

redis-cli> INCR counter // 键 counter 不存在,先初始化为 0,再递增 (integer) 1 redis-cli> INCR counter // 再次递增 (integer) 2 redis-cli> GET counter // 获取键 counter 的值 "2" redis-cli> SET not_a_number "abc" OK redis-cli> INCR not_a_number // 对非数字字符串执行 INCR 操作,报错 (error) ERR value is not an integer or out of range

2. DECR 命令:将键的值原子性地递减 1

DECR key

  • 作用: 将键存储的值减去 1。如果键不存在,则先将键的值初始化为 0,再执行递减操作。如果键的值不是整数类型,则会返回错误。

  • 返回值: 递减后的值。

代码示例:

redis-cli> SET initial_value 10 OK redis-cli> DECR initial_value // 递减 (integer) 9 redis-cli> DECR initial_value // 再次递减 (integer) 8 redis-cli> GET initial_value "8"

3. INCRBY 命令:将键的值原子性地递增指定的整数

INCRBY key increment

  • 作用: 将键存储的值加上指定的整数 increment。如果键不存在,则先将键的值初始化为 0,再执行递增操作。如果键的值不是整数类型,则会返回错误。

  • 返回值: 递增后的值。

代码示例:

redis-cli> INCRBY score 50 // 键 score 不存在,初始化为 0,然后加 50 (integer) 50 redis-cli> INCRBY score 25 // 再次递增 25 (integer) 75 redis-cli> GET score "75"

4. DECRBY 命令:将键的值原子性地递减指定的整数

DECRBY key decrement

  • 作用: 将键存储的值减去指定的整数 decrement。如果键不存在,则先将键的值初始化为 0,再执行递减操作。如果键的值不是整数类型,则会返回错误。

  • 返回值: 递减后的值。

代码示例:

redis-cli> SET product_stock 100 OK redis-cli> DECRBY product_stock 10 // 减少库存 10 (integer) 90 redis-cli> DECRBY product_stock 20 // 再次减少库存 20 (integer) 70 redis-cli> GET product_stock "70"

5. INCRBYFLOAT 命令:将键的值原子性地递增指定的浮点数

INCRBYFLOAT key increment

  • 作用: 将键存储的值加上指定的浮点数 increment。如果键不存在,则先将键的值初始化为 0,再执行递增操作。如果键的值不是数字类型,则会返回错误。

  • 返回值: 递增后的值,以字符串形式返回。

代码示例:

redis-cli> INCRBYFLOAT price 1.5 // 键 price 不存在,初始化为 0,然后加 1.5 "1.5" redis-cli> INCRBYFLOAT price 0.25 // 再次递增 0.25 "1.75" redis-cli> GET price "1.75"

2.1.4 字符串的字符串操作命令

Redis 字符串还提供了一些用于字符串操作的命令,例如追加、获取长度、获取子字符串、设置子字符串等。

1. APPEND 命令:将 value 追加到键的字符串值的末尾

APPEND key value

  • 作用: 如果键已经存在并且是一个字符串,则将 value 追加到字符串值的末尾。如果键不存在,则将键的值设置为 value

  • 返回值: 追加后的字符串的长度。

代码示例:

redis-cli> SET my_string "Hello" OK redis-cli> APPEND my_string " World" // 追加 " World" (integer) 11 redis-cli> GET my_string "Hello World" redis-cli> APPEND new_string "First append" // 键 new_string 不存在,相当于 SET new_string "First append" (integer) 12 redis-cli> GET new_string "First append"

2. STRLEN 命令:获取键的字符串值的长度

STRLEN key

  • 作用: 返回键的字符串值的长度。

  • 返回值: 如果键存在且值为字符串,则返回字符串长度。如果键不存在,则返回 0

代码示例:

redis-cli> SET my_long_string "This is a long string" OK redis-cli> STRLEN my_long_string // 获取字符串长度 (integer) 21 redis-cli> STRLEN non_existent_string // 获取不存在的键的字符串长度 (integer) 0

3. GETRANGE 命令:获取字符串值的子字符串

GETRANGE key start end

  • 作用: 返回字符串值从 start 偏移量到 end 偏移量(包含 startend)的子字符串。偏移量从 0 开始计数。可以使用负数偏移量,-1 表示字符串的最后一个字符,-2 表示倒数第二个字符,以此类推。

  • 返回值: 子字符串。

代码示例:

redis-cli> SET my_substring "This is a substring example" OK redis-cli> GETRANGE my_substring 0 3 // 获取索引 0 到 3 的子字符串 "This" redis-cli> GETRANGE my_substring 5 -1 // 获取索引 5 到末尾的子字符串 "is a substring example" redis-cli> GETRANGE my_substring 0 -1 // 获取整个字符串 "This is a substring example" redis-cli> GETRANGE my_substring 10 100 // end 偏移量超出字符串长度,只返回到字符串末尾的子字符串 "string example"

4. SETRANGE 命令:覆盖字符串值的子字符串

SETRANGE key offset value

  • 作用: 从指定的 offset 偏移量开始,用 value 覆盖键的字符串值的一部分。如果 offset 大于字符串的当前长度,Redis 会用空字节 (zero-byte, \x00) 填充字符串,使其长度达到 offset,然后再进行覆盖。如果键不存在,则会创建一个新的字符串。

  • 返回值: 修改后的字符串的长度。

代码示例:

redis-cli> SET my_original_string "Hello World" OK redis-cli> SETRANGE my_original_string 6 "Redis" // 从索引 6 开始,用 "Redis" 覆盖 (integer) 11 redis-cli> GET my_original_string "Hello Redis" redis-cli> SETRANGE my_original_string 20 "Beyond" // offset 大于字符串长度,会用空字节填充 (integer) 26 redis-cli> GET my_original_string "Hello Redis\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Beyond" redis-cli> SETRANGE new_key 5 "Initial" // 键 new_key 不存在,创建新字符串并用空字节填充 (integer) 12 redis-cli> GET new_key "\x00\x00\x00\x00\x00Initial"

2.1.5 字符串的位操作命令

Redis 字符串是二进制安全的,这意味着我们可以将字符串值视为位数组,并进行位操作。

1. SETBIT 命令:设置字符串值的指定偏移量上的位

SETBIT key offset value

  • 作用:key 所储存的字符串值,设置或清除指定 offset 偏移量上的位 (bit)。offset 从 0 开始计数。value 可以是 01

  • 返回值: 返回指定偏移量原来储存的位值。

代码示例:

redis-cli> SETBIT bitkey 7 1 // 设置第 7 位(从 0 开始)为 1, 相当于将 ASCII 码的 'A' 的二进制表示的最后一位设置为 1 (integer) 0 // 原来第 7 位是 0 redis-cli> GETBIT bitkey 7 // 获取第 7 位的值 (integer) 1 redis-cli> GET bitkey // 查看字符串的值,此时字符串的值相当于 ASCII 码的 'A' (二进制 01000001) "@" // ASCII 码 64 是 '@',二进制 01000000,设置第 7 位为 1 后变为 01000001,ASCII 码 65 是 'A'。这里显示 '@' 是因为 ASCII 码 64 的字符显示为 '@',而 65 的字符显示为 'A'。 redis-cli> SETBIT bitkey 7 0 // 将第 7 位设置为 0 (integer) 1 // 原来第 7 位是 1 redis-cli> GETBIT bitkey 7 // 获取第 7 位的值 (integer) 0 redis-cli> GET bitkey // 查看字符串的值,此时字符串的值相当于 ASCII 码的 '@' "@"

2. GETBIT 命令:获取字符串值的指定偏移量上的位

GETBIT key offset

  • 作用: 返回 key 所储存的字符串值,在指定 offset 偏移量上的位 (bit)。

  • 返回值: 指定偏移量上的位值 (01)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0

代码示例:

redis-cli> SETBIT getbitkey 5 1 (integer) 0 redis-cli> GETBIT getbitkey 5 // 获取第 5 位的值 (integer) 1 redis-cli> GETBIT getbitkey 100 // offset 超出字符串长度,返回 0 (integer) 0 redis-cli> GETBIT non_existent_bitkey 0 // key 不存在,返回 0 (integer) 0

3. BITCOUNT 命令:计算给定范围内被设置为 1 的位的数量

BITCOUNT key [start end]

  • 作用: 计算给定字符串中,被设置为 1 的位的数量。可以使用 startend 参数来限制计数范围,单位是字节,而不是位。

  • 返回值: 被设置为 1 的位的数量。

代码示例:

redis-cli> SET bitcountkey "\xff\xf0\x00" // 设置一个包含多个 '1' 位的字符串 (二进制 11111111 11110000 00000000) OK redis-cli> BITCOUNT bitcountkey // 计算整个字符串中 '1' 位的数量 (integer) 12 // \xff 有 8 个 1, \xf0 有 4 个 1, \x00 有 0 个 1, 总共 12 个 1 redis-cli> BITCOUNT bitcountkey 0 0 // 计算第一个字节中 '1' 位的数量 (integer) 8 // \xff 有 8 个 1 redis-cli> BITCOUNT bitcountkey 1 1 // 计算第二个字节中 '1' 位的数量 (integer) 4 // \xf0 有 4 个 1

4. BITOP 命令:对多个字符串值执行位运算

BITOP operation destkey key [key ...]

  • 作用: 对一个或多个字符串值执行位运算,并将结果保存到 destkey 中。operation 可以是 AND, OR, XOR, NOT

    • AND: 与运算

    • OR: 或运算

    • XOR: 异或运算

    • NOT: 非运算 (只支持单个 key)

  • 返回值: 结果字符串的长度,等于最长输入字符串的长度。

代码示例:

redis-cli> SET key1 "foo" // "foo" 的 ASCII 码二进制表示为 01100110 01101111 01101111 OK redis-cli> SET key2 "bar" // "bar" 的 ASCII 码二进制表示为 01100010 01100001 01110010 OK redis-cli> BITOP AND destkey key1 key2 // 对 key1 和 key2 进行 AND 运算 (integer) 3 redis-cli> GET destkey // 结果为 "bab", ASCII 码二进制表示为 01100010 01100001 01100010 "bab" redis-cli> BITOP OR destkey2 key1 key2 // 对 key1 和 key2 进行 OR 运算 (integer) 3 redis-cli> GET destkey2 // 结果为 "f`r", ASCII 码二进制表示为 01100110 01100000 01110010 "f`r" redis-cli> BITOP XOR destkey3 key1 key2 // 对 key1 和 key2 进行 XOR 运算 (integer) 3 redis-cli> GET destkey3 // 结果为 "\x00\x11\x0f", ASCII 码二进制表示为 00000000 00010001 00001111 "\x00\x11\x0f" redis-cli> BITOP NOT destkey4 key1 // 对 key1 进行 NOT 运算 (integer) 3 redis-cli> GET destkey4 // 结果为 "\x99\x90\x90", ASCII 码二进制表示为 10011001 10010000 10010000 "\x99\x90\x90"

2.1.6 字符串的批量操作命令

为了提高效率,Redis 提供了批量操作命令,可以一次性操作多个字符串键。

1. MSET 命令:同时设置多个键值对

MSET key value [key value ...]

  • 作用: 同时设置多个键值对。这是一个原子性操作,所有键值对要么都设置成功,要么都设置失败。

  • 返回值: 总是返回 OK

代码示例:

redis-cli> MSET key1 "value1" key2 "value2" key3 "value3" // 同时设置三个键值对 OK redis-cli> GET key1 "value1" redis-cli> GET key2 "value2" redis-cli> GET key3 "value3"

2. MGET 命令:同时获取多个键的值

MGET key [key ...]

  • 作用: 同时获取多个键的值。

  • 返回值: 一个包含所有给定键的值的列表。如果某个键不存在,则对应的值为 nil

代码示例:

redis-cli> MGET key1 key2 key3 non_existent_key // 同时获取四个键的值 1) "value1" 2) "value2" 3) "value3" 4) (nil) // non_existent_key 不存在,返回 nil

2.1.7 字符串的应用场景

Redis 字符串由于其简单高效的特性,被广泛应用于各种场景:

  • 缓存: 缓存热点数据,例如网页内容、API 响应、数据库查询结果等,提高应用性能。

  • 计数器: 利用 INCRDECR 等原子性操作实现各种计数功能,例如网站访问量统计、点赞数、评论数等。

  • 会话管理: 存储用户会话信息,例如用户 ID、登录状态、购物车信息等。

  • 限流: 利用计数器和过期时间实现简单的限流策略,防止恶意请求或突发流量冲击系统。

  • 分布式锁: 虽然 Redis 官方推荐使用 Redlock 实现分布式锁,但使用 SET key value NX EX seconds 命令也可以实现简单的分布式锁。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U