7.Redis string字符串
7.1 string字符串数据结构
-
string(字符串)结构是 Redis 中最简单的数据类型。Redis 所有数据类型都是以 key 作为键,通过检索这个 key 就可以获取相应的 value 值。Redis 存在多种数据类型,比如字符串、列表、哈希散列等,它们对应的 value 结构各不相同。
-
Redis 使用标准 C 语言编写,但在存储字符时,Redis 并未使用 C 语言的字符类型,而是自定义了一个特殊结构 SDS(Simple Dynamic String)即简单动态字符串,这是一个可以修改的内部结构,非常类似于 Java 的 ArrayList。
-
SDS动态字符串:结构定义如下:
struct sdshdr{
//记录buf数组中已使用字符的数量,等于 SDS 保存字符串的长度
int len;
//记录 buf 数组中未使用的字符数量
int free;
//字符数组,用于保存字符串
char buf[];
从结构体可以看出,Redis string 将字符串存储到字符类型的
buf[]
中,并使用len
、free
对buf[]
数组的长度和未使用的字符数进行描述。
SDS 字符串的结构示意图:
该图存储了一个
len
为 4 的 “java\0”字符串,并且未使用的字符数free
为 0。 buf 数组存储的字符串仍然以 C语言字符格式的“\0”结尾的,这样做的目的是为了能够重用 C语言库 <string.h> 中的部分函数。
- 分配冗余空间:string 采用了预先分配冗余空间的方式来减少内存的频繁分配,如下图所示:
Redis 每次给 string 分配的空间都要大于字符串实际占用的空间,这样就在一定程度上提升了 Redis string 存储的效率,比如当字符串长度变大时,无需再重新申请内存空间。
- string自动扩容:当字符串所占空间小于 1MB 时,Redis 对字符串存储空间的扩容是以成倍的方式增加的;而当所占空间超过 1MB 时,每次扩容只增加 1MB。Redis 字符串允许的最大值字节数是 512 MB。
7.2 字符串命令
- 通过相关字符串命令对其进行操作,比如设置、检索、删除等等。操作字符串的命令格式
redis 127.0.0.1:6379> COMMAND KEY_NAME
#COMMAND:表示字符串的命令;
#KEY_NAME:表示 key(键)的名称。
- 利用 Redis 客户端给出的自动语法提示,比如
SET
命令的格式如下:
127.0.0.1:6379> SET key value [EX seconds|PX milliseconds] [NX|XX]
-
其中
[]
内代表可选参数,其含义如下所示:- EX seconds:设置指定的过期时间,以秒为单位;
- PX milliseconds:设置指定的过期时间,以毫秒为单位;
- NX:先判断 key 是否存在,如果 key 不存在,则设置 key 与 value;
- XX:先判断 key 是否存在,如果 key 存在,则重新设置 value。
-
SET
命令演示:在 key 不存在的情况下设置过期时间为 60s:
#key的过期时间为60s,过期后自动删除
remote:0>set name tony ex 60 nx
"OK"
# 查询 key 对应的值
remote:0>get name
"tony"
7.3 常用命令
命令 | 说明 |
---|---|
SET key value | 用于设定指定键的值。 |
GET key | 用于检索指定键的值。 |
GETRANGE key start end | 返回 key 中字符串值的子字符。start从0开始 |
GETSET key value | 将给定 key 的值设置为 value,并返回 key 的旧值,即先get再set。 |
GETBIT key offset | 对 key 所存储的字符串值,获取其指定偏移量上的位(bit)。 |
MGET key1 [key2…] | 批量获取一个或多个 key 所存储的值,减少网络耗时开销。 |
SETBIT key offset value | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 |
SETEX key seconds value | 将值 value 存储到 key中 ,并将 key 的过期时间设为 seconds (以秒为单位)。是一步操作,保证了原子性 |
SETNX key value | 当 key 不存在时设置 key 的值。用于分布式锁,保证这个值存在,不会被覆盖+乐观锁。有值加锁,可当版本号 |
SETRANGE key offset value | 从偏移量 offset 开始,使用指定的 value 覆盖、替换的 key 所存储的部分字符串值。 |
STRLEN key | 返回 key 所储存的字符串值的长度。 |
MSET key value [key value …] | 该命令允许同时设置多个键值对。 |
MSETNX key value [key value …] | 当指定的 key 都不存在时,用于设置多个键值对。 |
PSETEX key milliseconds value | 此命令用于设置 key 的值和过期时间(以毫秒为单位)。 |
INCR key | 将 key 所存储的整数值加 1。自增 |
INCRBY key increment | 将 key 所储存的值加上给定的递增值(increment)。设置步长,指定增量 |
INCRBYFLOAT key increment | 将 key 所储存的值加上指定的浮点递增值(increment)。 |
DECR key | 将 key 所存储的整数值减 1。自减 |
DECRBY key decrement | 将 key 所储存的值减去给定的递减值(decrement)。设置步长,指定减量 |
APPEND key value | 该命令将 value 追加到 key 所存储值的末尾。 |
- Redis string 的
SET/GET
命令只能一次设置/查询一个键值对,这样虽然简单,但是效率不高。为了提高命令的执行效率,Redis 提供了可以批量操作多个字符串的读写命令 MSET/MGET(“M”代表“Many”),它们允许一次性设置或查询多个键值对,这样就有效地减少了网络耗时。
7.4 SET、GET命令
- SET 命令用于设置 key 存储的值,当 key 已经存储了其他值时, SET 命令会将原值覆盖,重新设置新值。GET 命令返回 key 所存储的字符串值。如果 key 不存在则返回 null,若 key 存储的不是一个字符串类型的值,将返回一个错误,因为 GET 命令只能处理字符串。 命令可用版本:>= 1.0.0
SET 命令在 Redis 2.6.12 版本做了参数的扩充,允许同时使用
EX
和NX
参数对 key 进行设置。
- 基本语法如下:
#SET 命令的基本语法如下:
127.0.0.1:6379>SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
#GET 命令的基本语法如下:
GET key
-
参数说明:
- EX second:设置键的过期时间为 second 秒。SET key value EX second 效果等同于 SETEX key second value。
- PX millisecond:设置键的过期时间为毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecond value。
- NX:只在键不存在时,才对键进行设置操作。SET key value NX 效果等同于 SETNX key value。
- XX:只在键已经存在时,才对键进行设置操作。
-
SET返回值:在 Redis 2.6.12 版本以前, SET 命令总是返回 OK 。从 Redis 2.6.12 版本开始, SET 在设置操作成功完成时,才返回 OK 。如果设置了 NX 或者 XX 参数,但因为条件没达到而造成设置操作未执行,那么命令返回 NULL Bulk Reply。
-
GET返回值当 key 不存在时,返回 null ,否则,返回 key 的值。如果 key 不是字符串类型,那么返回一个错误。
-
命令演示:
#使用EX和NX设置key
remote:0>set url www.baidu.com ex 60 nx
"OK"
remote:0>set url www.baidu.com px 600 xx
"OK"
#对已经存在的键进行设置
remote:0>set name marry
"OK"
#获取存储的值
remote:0>get name
"marry"
#key不存在
remote:0>get urls
null
#列表类型的key
remote:0>lpush course java php python
"3"
#返回错误,get只能操作字符串类型的key
remote:0>get course
"WRONGTYPE Operation against a key holding the wrong kind of value"
7.5 SETBIT、GETBIT命令
- SETBIT 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于 value,可以是 0 或者是 1 。
- 当 key 不存在时,自动生成一个新的字符串值。字符串会进行伸展以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。offset 参数必须大于或等于 0 ,小于 2^32 (bit 被限制在 512 MB 之内)。SETBIT 命令可用版本:>= 2.2.0
- GETBIT 命令对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0。GETBIT 命令可用版本:>= 2.2.0
提示:如果 offset 偏移量的值较大,计算机进行内存分配时可能会造成 Redis 服务器被阻塞。
- 命令的基本语法如下:
#SETBIT 命令#SETBIT 命令的基本语法如下:
setbit key offset value
#GETBIT 命令的基本语法如下:
GETBIT key offset
-
SETBIT 命令的返回值指定了偏移量原来储存的位。
-
GETBIT命令的返回值:字符串值指定偏移量上的位(bit)。
-
命令演示
#setbit key值的偏移量
remote:0>SETBIT mybit 0 1
"0"
remote:0>SETBIT mybit 1 1
"0"
remote:0>SETBIT mybit 2 0
"0"
127.0.0.1:6379> getbit mybit 0
(integer) 1
127.0.0.1:6379> getbit mybit 1
(integer) 1
127.0.0.1:6379> getbit mybit 2
(integer) 0
127.0.0.1:6379> get mybit
"\xd0"
#key默认各bit位初始化为0
#对不存在的 offset 进行 GETBIT, 返回 0
remote:0>getbit mybit 200
"0"
#对不存在的 key 或者不存在的 offset 进行 GETBIT, 返回 0
remote:0>exists mybits
"0"
remote:0>getbit mybits 10
"0"
#对已存在的 offset 进行 GETBIT
remote:0>setbit mybit 3 1
"0"
remote:0>getbit mybit 3
"1"
7.6 BITCOUNT命令
- BITCOUNT 命令用于计算给定字符串中,被设置为 1 的比特位数量。一般情况下,给定的整个字符串都会被计数,通过指定 start 或 end 参数,就可以让计数只在特定的位上进行。
提示:start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。start 从0开始
- 如果 key 不存在,则会被当成空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。命令可用版本:>= 2.6.0。 BITCOUNT 命令的基本语法如下:
BITCOUNT key [start end]
- 返回值:被设置为 1 的位的数量。命令演示
#setbit key值的偏移量
remote:0>SETBIT mybit 0 1
"0"
remote:0>SETBIT mybit 1 1
"0"
remote:0>SETBIT mybit 2 0
"0"
remote:0>SETBIT mybit 3 1
"0"
#统计1的数量
remote:0>bitcount mybit 0 3
"3"
remote:0>bitcount mybit 0 -1
"3"
#不存在的key进行BITCOUNT操作
remote:0>bitcount mybits 0 3
"0"
7.7 SETRANGE、GETRANGE命令
-
SETRANGE 命令用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始。如果 key 原来储存的字符串长度比偏移量小,比如字符串只有 5 个字符长,但你设置的 offset 是 8,那么原字符和偏移量之间的空白字符将用零字节(“\x00” )来填充。
-
最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆以内,如果需要使用比这更大的空间,可以使用多个 key 来实现 。
-
注意:当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会造成服务器阻塞。命令可用版本:>= 2.2.0
-
GETRANGE 命令用于截取一定长度的 value返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内的闭区间)。负数偏移量表示从字符串末尾开始计数,-1 表示最后一个字符,-2 表示倒数第二个,以此类推。GETRANGE 子字符串的长度大小(range)不能超过实际字符串的长度。命令可用版本:>= 2.4.0
-
基本语法如下:
#SETRANGE 命令的基本语法如下:
SETRANGE key offset value
#参数说明
KEY_NAME:指 key 的名字;
OFFSET:指初始偏移量;
VALUE:指要替换成的字符串。
#GETRANGE 命令的基本语法如下:
GETRANGE key start end
-
SETRANGE 命令的返回值:被修改之后的字符串总长度 。
-
GETRANGE 命令的返回值:截取后得到的子字符串。
-
命令演示:
remote:0>set pwd 123456
"OK"
remote:0>get pwd
"123456"
remote:0>setrange pwd 6 abcdef
"12"
remote:0>get pwd
"123456abcdef"
#key储存的字符串长度比偏移量小时,如何覆盖
remote:0>set pwd 123456
"OK"
remote:0>setrange pwd 8 abcdef
"14"
remote:0>get pwd
123456\x00\x00abcdef
remote:0>get pwd
"123456abcdef"
remote:0>getrange pwd 1 8
"23456abc"
remote:0>getrange pwd 1 -1
"23456abcdef"
remote:0>getrange pwd 1 -2
"23456abcde"
remote:0>getrange pwd 1 -3
"23456abcd"
#不支持从负数到正数,或者负数到负数
remote:0>getrange pwd -1 -3
- 在 2010 年的一台 Macbook Pro 上,设置偏移量为 536870911(512MB 内存分配),耗时约 300 毫秒,设置偏移量为 134217728(128MB 内存分配),耗时约 80 毫秒,设置偏移量 33554432(32MB 内存分配),耗时约 30 毫秒,设置偏移量为 8388608(8MB 内存分配),耗时约 8 毫秒。
注意:若首次内存分配成功之后,再对同一个 key 调用 SETRANGE 命令,无须重新分配内存。
7.8 SETEX命令
-
SETEX 命令为 key 设置 value 值,并将 key 的过期时间设为 seconds (以秒为单位)。如果 key 已经存在,那么将覆盖 key 原来的值。SETEX 命令与 PSETEX 命令类似,不过后者以毫秒(milliseconds)为单位。命令可用版本:>= 2.0.0
-
SETEX 命令的基本语法如下:
SETEX key seconds value
-
ETEX 命令的返回值设置成功时返回 OK,若 second 参数不符合要求,则会返回一个错误,比如设置成了负数或者浮点数。
-
命令演示:
remote:0>setex url 60 links
"OK"
remote:0>get url
"links"
#覆盖成功
remote:0>setex url 60 www.baidu.com
"OK"
#返回错误
remote:0>setex url -60 www.baidu.com
"ERR invalid expire time in 'setex' command"
remote:0>setex url 60.0 www.baidu.com
"ERR value is not an integer or out of range"
7.9 STRLEN命令
- STRLEN 命令返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。命令可用版本:>=2.2.0。SETNX 命令的基本语法如下:
STRLEN key
- SETNX 命令返回字符串值的长度。当 key 不存在时,返回 0。命令演示
remote:0>setnx url www.baidu.com
"1"
#获取长度
remote:0>strlen url
"13"
#若key不存在,则长度为 0
remote:0>strlen urls
"0"
7.10 SETNX命令
-
SETNX 命令,当且仅当给定的 key 不存在的时候,才创建 key,并为其设置 value 值。如果 key 已经存在,则命令执行失败。命令可用版本:>= 1.0.0
-
SETNX 命令的基本语法如下:
SETNX key value
- SETNX 命令的返回值设置成功,返回 1;设置失败,返回 0 。命令演示
remote:0>setnx url www.baidu.com
"1"
#setnx命令,当key存在时,不可以覆盖
remote:0>setnx url links
"0"
remote:0>get url
"www.baidu.com"
7.11 GETSET命令
- GETSET 命令将给定 key 的值设置为 value,并且返回 key 的旧值(old value)。先get在set。 命令可用版本:>= 1.0.0。GETSET 命令的基本语法如下:
GETSET key value
- GETSET 命令返回给定 key 的旧值,若 key 不存在则返回 null;当 key 存在但不是字符类型是,返回一个错误。命令演示
#类似juc中的cas自旋锁,比较并交换,在数据结构上是相同的java/高并发
remote:0>get pwd
"123456abcdef"
remote:0>getset pwd 12345678
"123456abcdef"
#key不存在
remote:0>getset pwds 12345678
null
#设置新值并返回旧值
remote:0>getset pwds abcdefg
"12345678"
7.12 MSET、MGET命令
-
MSET 命令用于同时设置一个或多个 key-value 键值对,MSET 命令可用版本:>= 1.0.1。MGET 命令返回一个或多个给定 key 的值,MGET 命令可用版本:>= 1.0.0。
-
命令的基本语法如下:
#MSET 命令的基本语法如下:
MSET key value [key value ...]
#MGET 命令的基本语法如下:
MGET key [key ...]
- MSET 命令返回 OK,MGET 命令返回所有 key 存储的 value 值。命令演示:
remote:0>mset name tony age 14
"OK"
remote:0>get name
"tony"
remote:0>get age
"14"
remote:0>mget name age
1) "tony"
2) "14"
- 设置对象的高级用法
set user:1 {name:zs,zge:10} #设置一个user:1对象,值位json字符来保存一个对象
# 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在redis是可行的。
remote:0>mset user:2:name zs user:2:age 15
"OK"
remote:0>mget user:2:name user:2:age
1) "zs"
2) "15"
7.13 MSETNX命令
- MSETNX 命令类似于 MSET 命令用于所有给定 key 都不存在时才能够执行成功,同时设置一个或多个 key-value 键值对。**该命令具有原子性,它执行结果只有两种:全部成功或者全部失败。**命令可用版本:>= 1.0.1。MSETNX 命令的基本语法如下:
MSETNX key value [key value ...]
- MSETNX 命令返回值:当所有 key 都成功设置时,返回 1,如果其中至少一个 key 已经存在,那么将设置失败,此时会返回 0。命令演示
#设置成功返回 1
remote:0>msetnx stu1 zs stu2 ls stu3 ww
"1"
#由于stu3已经存在,因此设置失败
remote:0>msetnx stu3 zs stu4 ls stu5remote:0> ww
"0"
remote:0>mget stu1 stu2 stu3
1) "zs"
2) "ls"
3) "ww"
7.14 APPEND命令
- APPEND 命令用于为指定的 key 追加值。如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。当 key 不存在时,它就为这个 key 设置 value 值,等同于 SET key value 操作。APPEND 命令可用版本:>= 2.0.0。该命令语法:
APPEND key value
- APPEND 命令的返回值:追加 value 之后, key 存储的字符串长度。命令演示
#确保name不存在,删除key
remote:0>del name
"1"
#自动创建,并设置value
remote:0>append name to
"2"
#追加到末尾
remote:0>append name ny
"4"
remote:0>get name
"tony"
- 时间序列(Time series):APPEND 命令可以为一系列定长(fixed-size)数据(sample)提供一种紧凑的表示方式,这种操作通常被应用于时间序列的表示上。命令的格式如下所示:
APPEND timeseries "fixed-size sample"
- 通过以下的方式可以访问时间序列的各项属性:
- STRLEN:给出时间序列中数据的数量;
- GETRANGE:可以用于随机访问;
- SETRANGE:可以用于覆盖或修改已存在的的时间序列。
这个方法的唯一缺陷就是只能增长时间序列,而不能缩短。因为 Redis 目前还没有对字符串进行修剪(tirm)的命令,但是,这种储存方式仍然节省了大量空间。
我们可以考虑使用 UNIX 时间戳作为时间序列的键名,这样可以避免单个 key 因为保存过大的时间序列而占用大量内存。
- 时间序列的例子
remote:0>append ts 0012
"4"
remote:0>append ts 0045
"8"
remote:0>getrange ts 0 3
"0012"
remote:0>getrange ts 4 7
"0045"
7.15 DECR、DECRBY命令
- DECR 命令对 key 中存储的数值做减 1 操作。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。DECR 命令可用版本:>= 1.0.0。
- DECRBY 命令对 key 中存储的数值做定减运算。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。INCRBY 命令可用版本:>= 1.0.0
注意:被操作的数值限制在 64 位(bit)有符号数字表示之内。
- 语法:
#DECR 命令的基本语法如下:
DECR key
#RBY 命令的基本语法如下:
DECRBY key increment
-
DECR 命令的返回值:执行 DECR 命令减 1 操作后 key 的值。
-
DECRBY 命令的返回值:减去 decrement 之后, key 存储的的数值。
-
命令演示:
remote:0>get age
"14"
remote:0>decr age
"13"
remote:0>decr age
"12"
#对不存在的key的值进行减1操作
remote:0>decr ages
"-1"
remote:0>decr ages
"-2"
#对可以进行指定数值的递减操作
remote:0>decrby age 5
"7"
#递增操作
remote:0>incr age
"8"
remote:0>incrby age 10
"26"
7.16 INCR、INCRBY命令
-
INCR 命令对 key 中存储的数值做加 1 操作。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。INCR 命令可用版本:>= 1.0.0
-
INCRBY 命令对 key 中存储的数值做增量运算。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。INCRBY 命令可用版本:>= 1.0.0
注意:被操作的数值限制在 64 位(bit)有符号数字表示之内。
- 语法
#INCR 命令的基本语法如下:
INCR key
#INCRBY 命令的基本语法如下:
INCRBY key increment
-
NCR 命令的返回值:执行 INCR 命令加 1 操作后 key 的值。
-
INCRBY 命令的返回值:加上 increment 之后, key 存储的的数值。
-
命令演示:
remote:0>get age
"26"
remote:0>incr age
"27"
remote:0>incr age
"28"
remote:0>incrby age 10
"38"
#key进行拓展使用,表明age是哪个对象的属性
remote:0>incr user:1:age
"28"
7.17 INCRBYFLOAT命令
- INCRBYFLOAT 命令对 key 中存储的数值加上浮点数增量。如果 key 不存在,那么 INCRBYFLOAT 会先将 key 的值设为 0 ,再执行加法操作。如果命令执行成功,那么 key 的值会被更新为新值,并且新值会以字符串的形式被返回。INCRBYFLOAT 命令可用版本:>= 2.6.0
- 无论是 key 存储的值,还是 increment 增量值,它们都可以使用指数符号来表示,比如 2.0e7 、 3e5 、 90e-2。
注意:INCRBYFLOAT 的计算结果最多只能表示小数点的后十七位。
- INCRBYFLOAT 命令的基本语法如下:
INCRBYFLOAT key increment
- INCRBYFLOAT 命令的返回值:加上 increment 浮点数后, key 存储的的数值。命令演示:
remote:0>set myfloat 314e-2
"OK"
remote:0>get myfloat
"314e-2"
#最多保留17位小数
remote:0>incrbyfloat myfloat 0
"3.14"
#小数加法。
remote:0>incrbyfloat myfloat 10.5
"13.64"
#表示负数,减法。
remote:0>incrbyfloat myfloat -2.5
"11.14"