Redis字符串存储字节序列,包括文本、序列化对象和二进制数组。String的数据结构为动态字符串,支持实现计数器和执行按位操作;而且它是二进制安全的,所以string可以包含任何数据,比如jpg图片或者序列化的对象。默认单个字符串value最多可以是512M。
1、获取/设置单/多个值、范围值
获取和设置单个值:SET、GET、GETDEL;设置获取多个值:MSET、MGET、MSETNX;获取范围值:GETRANGE、SETRANGE
(1)SET
SET
:**注意:**SET的选项可以替代SETNX, SETEX, PSETEX(ms), GETSET
,所以在未来版本中,这些命令可能会被弃用并最终删除。
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
NX/XX
:仅在该键不存在时设置该键,只在已经存在的情况下设置键值
#nx
redis> set k1 v1 nx
OK
redis> set k1 v2 nx
(nil)
redis> get k1
"v1"
#xx
redis> set k1 v2 xx
OK
redis> set k2 v2 xx
(nil)
redis> get k1
"v2"
redis> get k2
(nil)
GET
:返回存储在key的旧值,如果key不存在,则返回nil。如果key存储的值不是字符串,则返回错误并中止SET,等同于GETSET
命令
redis> set k1 v3 GET
"v2"
EX/PX
:设置指定的过期时间,以秒/毫秒为单位。
redis> set k1 v1 ex 8
OK
redis> ttl k1
(integer) 5
redis> set k1 v1 px 8000
OK
redis> ttl k1
(integer) 6
EXAT/PXAT
:设置密钥过期的指定Unix时间(时间戳),单位为秒。
#System.currentTimeMillis()/1000L
redis> set k1 v1 exat 1679933690
OK
redis> ttl k1
(integer) 19
#System.currentTimeMillis()
redis> set k2 v1 PXAT 1679933767463
OK
redis> ttl k2
(integer) 2
KKEPTTL
:保留之前的key配置的生存时间,不覆盖。
redis> set k1 v1 ex 50
OK
redis> ttl k1
(integer) 46
redis> set k1 v2 keepttl
OK
redis> ttl k1
(integer) 30
(2)GET:语法GET key
redis> GET nonexisting
(nil)
redis> SET mykey "Hello"
"OK"
redis> GET mykey
"Hello"
(3)GETDEL
语法:GETDEL key
,获取key的值并删除key,若不存在,则返回nil
redis> SET mykey "Hello"
"OK"
redis> GETDEL mykey
"Hello"
redis> GET mykey
(nil)
(4)mset / mget / msetnx
同时获取、设置多个值:
MSET key value [key value ...]
MGET key [key ...]
#只要存在有一个键已经存在,则返回0,且值全部不会被设置,相反返回1。
MSETNX key value [key value ...]
使用举例:
redis> mset k1 v1 k2 v2 k3 v3
OK
redis> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
redis> msetnx k3 va3 k4 v4 k5 v5
(integer) 0
redis> mget k3 k4 k5
1) "v3"
2) (nil)
3) (nil)
(5)getrange / setrange
getrange
:语法GETRANGE key start end
,获取指定区间范围内的值,类似between…and的关系,从零到负一表示全部。注意:start
<end
redis> set k1 abc123cdef
OK
redis> getrange k1 1 5
"bc123"
setrange
:语法SETRANGE key offset value
,设置指定区间范围内的值,是覆盖而非增加,格式:setrange key offset value
,如果设置的坐标之前没有值,将自动填充十六进制的0(\x00)
redis > set mystring abc
OK
redis > setrange mystring 1 de
(integer) 3
redis > get mystring
"ade"
redis > setrange mystring 5 test
(integer) 9
redis > get mystring
"ade\x00\x00test"
2、获取字符串长度/添加字符/截取字符串
strlen
:返回存储在key的字符串值的长度(字节数),当key不存在时为0。当key包含非字符串值时返回错误。
redis> set v2 ajsdjanda
OK
redis> strlen v2
(integer) 9
redis> strlen k2
(integer) 0
append
:将值追加到字符串的末尾。如果key不存在,先创建并将设置值,这种情况下,APPEND将类似于set。
redis> append v3 hello
(integer) 10
redis> get v3
"asdadhello"
substr
:语法:SUBSTR key start end
,返回key中指定范围的字符串值,由偏移量start和end决定,-1表示最后一个字符,-2表示倒数第二个字符,以此类推。
redis> get k1
"12312asdasdasd"
redis> substr k1 -2 2
""
redis> substr k1 -2 -1
"sd"
3、公共子串
LCS
命令实现了最长公共子序列算法,可用于评估字符串的相似程度。注意:匹配字符串中的字符不需要连续的。例如:“foa”,“foo"的LCS为"fo”。该算法在O(N*M)
时间内运行,其中N/M是第二个字符串的长度。
LCS key1 key2 [LEN] [IDX] [MINMATCHLEN min-match-len] [WITHMATCHLEN]
LEN
:获取两字符串的匹配长度
redis > MSET key1 ohmytext key2 mynewtext
OK
redis > LCS key1 key2 LEN
(integer) 6
IDX
:获取配置字符串的字符坐标,先按从尾到头匹配片段、片段中的起始字符坐标分开返回。
redis > LCS key1 key2 IDX
1) "matches"
2) 1) 1) 1) (integer) 4
2) (integer) 7
2) 1) (integer) 5
2) (integer) 8
2) 1) 1) (integer) 2
2) (integer) 3
2) 1) (integer) 0
2) (integer) 1
3) "len"
4) (integer) 6
MINMATCHLEN
:指定只返回长度大于或等于这个值的子序列
> LCS key1 key2 IDX MINMATCHLEN 4
1) "matches"
2) 1) 1) 1) (integer) 4
2) (integer) 7
2) 1) (integer) 5
2) (integer) 8
3) "len"
4) (integer) 6
WITHMATCHLEN
:用于在返回结果中包含每个匹配子序列的长度
> LCS key1 key2 IDX MINMATCHLEN 4 WITHMATCHLEN
1) "matches"
2) 1) 1) 1) (integer) 4
2) (integer) 7
2) 1) (integer) 5
2) (integer) 8
3) (integer) 4
3) "len"
4) (integer) 6
4、计数器、自增
**注意:**必须是数值才能进行加减,自增:INCR、INCRBY、INCRBYFLOAT;递减:DECR、DECRBY
INCR
:将存储在键上的数字增加一,返回自增后的值,INCR key
。如果key不存在,则在执行操作前先置0。如果键包含错误类型的值或包含不能表示为整数的字符串,则返回错误。此操作仅限于以10为基数的64位有符号整数。实现网页访问限制:
#计数器模式,网页访问限制
FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
ELSE
value = INCR(ip)
IF value == 1 THEN
EXPIRE(ip,1)
END
PERFORM_API_CALL()
END
在上面的代码中有一个并发问题。如果出于某种原因,客户端执行了INCR命令,但没有执行EXPIRE,key将被泄露,直到我们再次看到相同的IP地址。这个问题可以通过把带有可选的EXPIRE参数的INCR命令转换成一个Lua
脚本,然后用EVAL
命令发送给Redis来解决。
local current
current = redis.call("incr",KEYS[1])
if current == 1 then
redis.call("expire",KEYS[1],1)
end
INCRBY / INCRBYFLOAT
:语法INCRBY / INCRBYFLOAT key increment
,按增量递增存储在键上的数字,不存在同上,返回自增后的值。
redis> INCRby k1 2
(integer) 5
redis> INCRBYFLOAT mykey 0.1
"10.6"
redis> INCRBYFLOAT mykey -5
"5.6"
DECR
:语法DECR key
,将存储在键上的数字减1。不存在同上。
redis> decr k1
(integer) 4
DECRBY
:语法DECRBY key decrement
,以递减的方式递减存储在键上的数字。不存在同上。
redis> decrby k1 2
(integer) 2
5、数据结构
String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS),是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。