Redis 字符串

字符串操作相关命令

Redis 的命令及其选项时不区分大小写的(键以及值是区分大小写的),本文中采用 [] 表示可选项,命令中的关键字使用大写,参数值使用小写以便区分

常用命令

设置值

SET

自1.0.0起可用。

时间复杂度: O(1)

语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]
返回值:成功返回 OK 失败返回 nil
示例:
coderknock> SET testStringSet HelloWorld
OK
coderknock> GET testStringSet
"HelloWorld"

如果参数错误会抛出异常

说明:

该命令中的可选项解释如下:

  • EX seconds :为该键设置秒级过期时间。EX 为 "expire " 的缩写
  • PX milliseconds :为该键设置毫秒级过期时间
  • NX :键必须不存在,才可以设置成功,用于添加。NX 为 "Not eXists"的缩写
  • XX :与XX相反,键必须存在,才可以设置成功,用于更新

EX 以及 PX 选项比较好理解,下面只提供 NX 和 XX 的示例,请先查看命令然后根据上面的说明进行分析之后再查看下文的分析:

coderknock> SET testStringSet coderknock NX
(nil)
coderknock> GET testStringSet
"HelloWorld"
coderknock> SET testStringSetNX coderknock NX
OK
coderknock> GET testStringSetNX
"coderknock"
coderknock> SET testStringSetNX sanchan XX
OK
coderknock> SET testStringSetXX coderknock XX
(nil)
coderknock> GET testStringSetXX
(nil)
coderknock> GET testStringSetNX
"sanchan"
coderknock>

上面的示例中我们对之前设置的 testStringSet 再次进行设置并使用 NX 选项,发现返回值非 之前示例中的 OK 而变成了 nil (代表 SET 操作失败),查看 testStringSet 发现确实未更改,之后 SET 一个没有的 key 并且使用 NX 可以正常 SET。当我们使用 XX 选项添加一个新的 key时发现添加失败,修改已有的 key 成功。

Redis 还提供了 SETNX和 SETEX、PSETEX 三个个命令,相当于 SET 命令使用 NX 选项、 EX选项、PX选项时的情形。由于其特性,SETNX可以用作分布式锁的实现 https://redis.io/topics/distlock 官方给出了相关方法,但是这三个指令之后的版本可能会删除。

SETNX

SETNX 是 "SET if Not eXists" 的简写,

语法: SETNX key value
返回值:当设置成功时 返回 1 反之返回 0。【注意可选项与 SET 有区别,返回值也有区别】
示例:
coderknock> SETNX testSETNX SETNX
(integer) 1
coderknock> SETNX testSETNX a
(integer) 0
coderknock> GET testSETNX
"SETNX"
coderknock> SETNX testSETNXEX test 1 
(error) ERR wrong number of arguments for 'setnx' command

如果参数错误会抛出异常,例如上面示例的最后一行多了一个 1 的参数

SETEX

自2.0.0起可用。

时间复杂度: O(1)

语法:SETEX key seconds value
返回值:成功返回 OK

如果参数错误会抛出异常

示例:
coderknock> PSETEX mykey 1000 "Hello"
"OK"
coderknock> PTTL mykey
(integer) 999
coderknock> GET mykey
"Hello"
PSETEX

自2.0.0起可用。

时间复杂度: O(1)

语法:PSETEX key milliseconds value
返回值:成功返回 OK

PSETEX 与 SETEX很类似所以就不过多讲解了

示例:
coderknock> PSETEX mykey 1000 "Hello"
"OK"
coderknock> PTTL mykey
(integer) 999
coderknock> GET mykey
"Hello"

官方网站上有更详细的说明:SET 命令 SETEX命令 SETNX命令 PSETEX命令

获取值

GET

自1.0.0起可用。

时间复杂度: O(1)

语法:GET key
返回值:key 存在则返回 key 对应的值,反之返回 nil
示例:
coderknock> GET nonexisting
(nil)
coderknock> SET mykey "Hello"
"OK"
coderknock> GET mykey
"Hello"

批量设置值

MSET

自1.0.1起可用。

时间复杂度: O(N) 其中N是要设置的 key 的数量

语法:MSET key value [key value ...]
返回值:MSET 始终成功,不会有失败的情况,所以返回值始终是 OK
示例:
coderknock> MSET key1 "Hello" key2 "World"
"OK"
coderknock> GET key1
"Hello"
coderknock> GET key2
"World"
说明:

MSET是原子的,所有给定的键都是立即设置的。客户端不可能看到某些 key 被更新,而其他 key 没有更新。

MSETNX

自1.0.1起可用。

时间复杂度: O(N) 其中N是要设置的 key 的数量

语法:MSETNX key value [key value ...]
返回值:所有 key 都设置成功返回 1,设置失败返回 0
示例:
coderknock> MSETNX key1 "Hello" key2 "there"
(integer) 1
coderknock> MSETNX key2 "there" key3 "world"
(integer) 0
coderknock> MGET key1 key2 key3
1) "Hello"
2) "there"
3) (nil)
说明:

为给定的 key 设置各自的值。 即使只有一个 key 已经存在,MSETNX 也不会执行任何操作。

可以使用 MSETNX 这种语义来设置表示唯一逻辑对象的不同字段的不同 key ,以确保所有字段设置或都不设置。

MSETNX是原子的,所有给定的 key 都是一次设置的。客户端不可能看到某些 key 被更新,而其他 key 没有更新。

批量获取值

MGET

自1.0.0起可用。

时间复杂度: O(N) 其中N是要设置的 key 的数量

语法:MGET key [key ...]
返回值:按顺序返回所有 key 的值,如果有些键不存在,那么它的值会是 nil
示例:
coderknock> SET key1 "Hello"
"OK"
coderknock> SET key2 "World"
"OK"
coderknock> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)

批量操作的优点

批量操作能够提高程序的性能,如果不使用批量操作来执行 n 次操作则花费为:

n 次操作时间 = n 次网络时间 + n 次命令时间。

而使用批量操作后则只需要:

n次操作时间 = 1次 网络时间 + n 次命令时间

这样会节省很多网络开销,在大型项目中 网络开销往往是系统性能的瓶颈。需要注意的是,如果一次批处理数量太多可能导致 Redis 阻塞或者 网络阻塞。

计数

INCR

自1.0.1起可用。

时间复杂度: O(N) 其中N是要设置的 key 的数量

语法:INCR key

返回值:

INCR 命令用于对值做自增操作,返回结果分为三种情况:

  • 值不是整数,返回错误。
  • 值是整数,返回自增后的结果。
  • 键不存在,按照值为0自增,返回结果为1
示例:
coderknock> SET mykey "10"
"OK"
coderknock> INCR mykey
(integer) 11
coderknock> GET mykey
"11"
coderknock>

对一个不存在的键执行incr操作后,返回结果是1:

coderknock> EXISTS key
(integer) 0
coderknock> INCR key
(integer) 1
coderknock> INCR key
(integer) 2

如果值不是整数,那么会返回错误:

coderknock> SET hello world
OK
coderknock> INCR  hello
(error) ERR value is not an integer or out of range

除了 INCR 命令,Redis提供了 DECR(自减)、INCRBY(自增指定数字)、DECRBY(自减指定数字)、INCRBYFLOAT(自增浮点数):

DECR key
INCRBY key increment
DECRBY key decrement
INCRBYFLOAT key increment

很多存储系统和编程语言内部使用 CAS(Compare and Swap) 机制实现计数功能,会有一定的 CPU 开销,但在 Redis 中完全不存在这个问题,因为 Redis 是单线程架构,任何命令到了 Redis 服务端都要顺序执行。

##不常用命令

追加值

APPEND

自2.0.0起可用。

时间复杂度: O(1)

语法:APPEND key
说明:

如果 key 已经存在并且是字符串,则该命令将追加 value 到字符串的末尾。如果 key不存在,它将被创建并设置为空字符串,因此APPEND在这种特殊情况下 将类似于SET

返回值:

追加操作后的字符串长度。

示例:
coderknock> EXISTS mykey
(integer) 0
coderknock> APPEND mykey "Hello"
(integer) 5
coderknock> APPEND mykey " World"
(integer) 11
coderknock> GET mykey
"Hello World"

字符串长度

STRLEN

自2.2.0起可用。

时间复杂度: O(1)

语法:STRLEN key
说明:

返回存储在 key 中的字符串值的长度。key 保存非字符串值时返回错误。

返回值:

key 对应字符串值的长度,key 不存在时返回 0。

示例:
coderknock> SET mykey "Hello world"
"OK"
coderknock> STRLEN mykey
(integer) 11
coderknock> STRLEN nonexisting
(integer) 0

操作非字符串值时会报错:

coderknock> SADD test a
(integer) 1
coderknock> TYPE test
set
coderknock> STRLEN test
(error) WRONGTYPE Operation against a key holding the wrong kind of value

一个中文占用3个字节:

coderknock> SET hello "世界"
OK
coderknock> STRLEN hello
(integer) 6

设置并返回原值

GETSET

自1.0.0可用。

时间复杂度: O(1)

语法:GETSET key value
返回值:

返回 key 存储的旧值,当 key 不存在时返回 nil

说明:

以原子方式设置 key 到 value ,并返回存储的旧值 key。key 存在但不包含字符串时返回错误。

示例:
coderknock> SET mykey "Hello"
"OK"
coderknock> GETSET mykey "World"
"Hello"
coderknock> GET mykey
"World"
coderknock> GETSET test a
(error) WRONGTYPE Operation against a key holding the wrong kind of value
SETRANGE

自2.2.0起可用。

时间复杂度: O(1),不计算复制新字符串所需的时间。通常,这个字符串非常小,所以摊销的复杂度是O(1)。否则,复杂度为O(M),M为值参数的长度。

语法:SETRANGE key offset value
说明:

重写存储在 key 中的字符串中一部分内容,offset 指定的是替换开始的位置。如果 offset 大于 key 中值的长度,则以0字节填充字符串以达到偏移量 offset 。不存在的 key 被视为空字符串。

请注意,您可以设置的最大偏移量为2 ^ 29 -1(536870911),因为 Redis Strings 限制为512兆字节。如果您需要超出此尺寸,您可以使用多个键。
返回值:

修改后的字符串长度

示例:
coderknock> SET key1 "Hello World"
"OK"
coderknock> SETRANGE key1 6 "Redis"
(integer) 11
coderknock> GET key1
"Hello Redis"
coderknock> SETRANGE test 5 asf
(error) WRONGTYPE Operation against a key holding the wrong kind of value
coderknock> SET str 123456789
OK
coderknock> SETRANGE str 20 abv
(integer) 23
coderknock> GET str
"123456789\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00abv"
GETRANGE

自2.4.0起可用。

时间复杂度: O(N)其中N是返回字符串的长度。复杂性最终由返回的长度确定,但是由于从现有字符串创建子字符串非常高效的,因此可以将短字符串视为 O(1)。

语法:GETRANGE key start end

警告:此命令已重命名为 GETRANGE,在 Redis <= 2.0 的版本中调用 SUBSTR。

说明:

返回 key 由 start ,end(两者均包含)偏移量确定的字符串值的子字符串。可以使用负偏移量来提供从字符串末尾开始的偏移量。-1 表示最后一个字符,-2 表示倒数第二个等等。

该功能通过将结果范围限制为字符串的实际长度来处理超出范围的请求。(end 超出长度则只是返回到最后一个字符)

返回值:

截取后的字符串

示例:
coderknock> SET mykey "This is a string"
"OK"
coderknock> GETRANGE mykey 0 3
"This"
coderknock> GETRANGE mykey -3 -1
"ing"
coderknock> GETRANGE mykey 0 -1
"This is a string"
coderknock> GETRANGE mykey 10 100
"string"
coderknock> getrange mykey 100 1000
""

内部数据结构

Redis 中字符串的内部数据结构有 3 中:

  • int:8 个字节的长整数
  • embstr:小于等于 39 个字节的字符串 【存疑】
  • raw:大于 39 个字节的字符串

Redis 会根据当前值的类型和长度决定使用哪种内部数据接口实现。

整数类型:

coderknock> SET intKey 8653
OK
coderknock> OBJECT ENCODING intKey
"int"
coderknock> TYPE intKey
string

短字符串:

coderknock> SET embstrKey hello
OK
coderknock> OBJECT ENCODING embstrKey
"embstr"
coderknock> SET 39Key 123456789012345678901234567890123456789
OK
# 这里超过 8 字节,所以虽然是整数但是内部数据结构选择的是 embstr
coderknock> STRLEN 39Key
(integer) 39
coderknock> OBJECT ENCODING 39Key
"embstr"

长字符串:

coderknock> SET rawKey asdfghjklzxcvbnmqwertyuiopqwertyuiopasdfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OK
coderknock> OBJECT ENCODING 40Key
"raw"

典型应用场景

缓存功能

架构简析

计数

Session共享

在一个集群环境中,Web 服务器有多个,受负载均衡服务器管控,如果每个服务器分别存储各自的 Session 就会导致宕机或者切换服务器后 Session 丢失,用户需要重新登录。 其中一种解决方案就是将所有 Web 服务器的 Session 放到 Redis 中,从而实现无论具体服务器怎么切换 Session 都不会丢失。

限速

类似于计数功能,只是还利用了过期时间这一特性。

本人的直播课程在 7 月份就要开始了,希望小伙伴们支持一下,现在报名有优惠噢

https://segmentfault.com/l/1500000009894242

https://segmentfault.com/l/1500000009905148

转载于:https://my.oschina.net/coderknock/blog/915714

### 回答1: Redis 字符串Redis 中最基本的数据类型。它是一种键值对存储方式,键是字符串类型,值也是字符串类型。 Redis 字符串的底层实现是基于双向链表和字典(dictionary)的。在 Redis 中,所有的键值对都存储在一个字典中,字典中的每一个节点都是一个键值对,同时也是一个双向链表的节点。字典本身是一个哈希表,用于快速查找和插入键值对。 当 Redis 中的一个字符串被修改时,Redis 会将旧的字符串值从字典中删除,然后将新的字符串值插入到字典中。这样,就可以保证 Redis 字符串的原子性,同时也保证了字符串的高效存储。 总结一下,Redis 字符串的底层原理就是基于字典和双向链表实现的键值对存储方式。 ### 回答2: Redis 字符串的底层实现原理是基于简单动态字符串(SDS)和字典(dict)。 简单动态字符串(SDS)是 Redis 底层的字符串实现,它是一个动态分配的字符数组,并且可以在 O(1) 复杂度下进行字符串长度的获取和修改。SDS 的结构体中包含字符串指针、字符串长度、已分配内存长度等字段,通过这些字段可以方便地对字符串进行操作。 字典(dict)是 Redis 底层用于存储字符串键值对的数据结构。在 Redis 字符串中,键相当于字符串的名字,值则是存储的实际数据。字典采用哈希表作为底层实现,使用哈希函数将键映射到哈希桶中,以提高查找效率。在 Redis 中,哈希表的长度会根据实际数据的增加和删除进行动态扩容和缩容,以保证哈希表的平均负载因子不超过一个特定的值。 Redis 字符串的底层实现成为一个 SDS 字符串结构,它字典结构之间是相互独立的。当一个字符串被确定为一个键或值时,它会被存储在一个 SDSDICT 字典中,其中键为字符串本身,值则是一个指向 SDS 结构的指针。 总结来说,Redis 字符串的底层实现原理是基于简单动态字符串(SDS)和字典(dict)。SDS 是一个动态分配的字符数组,可以方便地进行字符串长度的获取和修改。而字典用于存储字符串键值对,通过哈希表提高查找效率。在 Redis 中,字符串被存储在一个 SDSDICT 字典中,其中键为字符串本身,值为指向 SDS 结构的指针。 ### 回答3: Redis字符串的底层原理是通过使用简单动态字符串(简称SDS)实现的。SDS是Redis自己实现的以C字符串结构为基础的字符串库,它解决了C字符串的一些限制,使得Redis可以支持更多的操作和功能。 在Redis中,每个字符串对象都由一个redisObject结构表示,该结构包含了一个指向SDS的指针和其他元数据。SDS结构由以下几部分组成: 1. len:记录字符串的长度,即字节数。 2. free:记录SDS结尾未使用的字节数,方便扩展字符串时无需重新分配内存。 3. buf:实际的字符数组,用于存储字符串的内容。 Redis字符串对象的底层原理有以下几个特点: 1. 动态扩展:SDS提供了高效的内存扩展机制,当字符串长度增加时,可以动态调整内存大小,避免了频繁的内存重新分配操作,提高了性能。 2. O(1)时间复杂度:SDS支持通过偏移量来直接访问字符串的某一位置的字符,所以读取和修改字符串的某一位置的操作时间复杂度为O(1)。 3. 惰性空间释放:当从字符串中删除部分字符时,SDS并不立即释放所占用的内存,而是通过将free字段增加相应的值来标记该内存已被释放,以备将来再次使用。 4. 兼容C字符串:SDS结构C字符串之间可以相互转换,方便Redis其他系统进行兼容。 总的来说,Redis字符串的底层原理是通过使用SDS实现的,SDS提供了高效的内存扩展和访问机制,使得Redis可以高效地处理字符串操作,提高了性能和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值