Redis 数据类型之字符串(String)类型

 2016年08月14日    446     声明


  1. 字符串(String)类型
  2. 字符串类型中的命令及使用

1. 字符串(String)类型

字符串(String)是Redis 中最基本、使用最多的一种数据类型。字符串类型是最简单的一种key-value结构,但其可存储的值(value)不仅限于字符串,也可以是数字、序列化的对象等任何类型的数据。

一个字符串类型的value最大长度为512 M

对于字符串类型,我们可以对其设置/取值、获取字符串长度、做为计数器进行自增/自减操作等。


2. 字符串类型中的命令及使用

2.1 设置与取值

设置一个字符串类型数据,就是对key-value结构赋值,设置值的同时也可以指定该key的有效期。设置值后,可以通过key获取其值。

2.1.1 SET - 设置值

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

设置key值为字符串value。如果key已存在,则覆盖其值并忽略原类型;如果原key已设置TTL(生存时间),SET操作会清除TTL。

可选参数:

  • [EX seconds] - 设置key的过期时间为seconds秒。SET key value EX second等同于SETEX key second value
  • PX millisecond - 设置key的过期时间为millisecond毫秒。SET key value PX millisecond等同于PSETEX key millisecond value
  • NX - 只在key不存在时才进行设置。SET key value NX等同于SETNX key value
  • XX - 只在key存在时才进行设置

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:操作成功,返回OK。如果设置了NXXX,操作未执行时返回NULL Bulk Reply
# 对不存在的键进行设置
redis> SET key "value"
OK
redis> GET key
"value"

# 对已存在的键进行设置
redis> SET key "itbilu.com"
OK
redis> GET key
"itbilu.com"

# 使用 EX 选项
redis> SET key-with-expire-time "hello" EX 10086
OK
redis> GET key-with-expire-time
"hello"
redis> TTL key-with-expire-time
(integer) 10069


# 使用 PX 选项
redis> SET key-with-pexpire-time "moto" PX 123321
OK
redis> GET key-with-pexpire-time
"moto"
redis> PTTL key-with-pexpire-time
(integer) 111939

# 使用 NX 选项
redis> SET not-exists-key "value" NX
OK      # 键不存在,设置成功
redis> GET not-exists-key
"value"
redis> SET not-exists-key "new-value" NX
(nil)   # 键已经存在,设置失败
redis 127.0.0.1:6379> GEt not-exists-key
"value" # 维持原值不变

# 使用 XX 选项
redis> EXISTS exists-key
(integer) 0
redis> SET exists-key "value" XX
(nil)   # 因为键不存在,设置失败
redis> SET exists-key "value"
OK      # 先给键设置一个值
redis> SET exists-key "new-value" XX
OK      # 设置新值成功
redis> GET exists-key
"new-value"

# NX 或 XX 可以和 EX 或者 PX 组合使用
redis> SET key-with-expire-and-NX "hello" EX 10086 NX
OK
redis> GET key-with-expire-and-NX
"hello"
redis> TTL key-with-expire-and-NX
(integer) 10063
redis> SET key-with-pexpire-and-XX "old value"
OK
redis> SET key-with-pexpire-and-XX "new value" PX 123321
OK
redis> GET key-with-pexpire-and-XX
"new value"
redis> PTTL key-with-pexpire-and-XX
(integer) 112999

# EX 和 PX 可以同时使用,但后面的选项会覆盖前面的选项
redis 127.0.0.1:6379> SET key "value" EX 1000 PX 5000000
OK
redis> TTL key
(integer) 4993  # 这是 PX 参数设置的值
redis> SET another-key "value" PX 5000000 EX 1000
OK
redis> TTL another-key
(integer) 997   # 这是 EX 参数设置的值


2.1.2 SETNX - key不存在则设置其值

SETNX key value

key不存在时,设置key的值为value

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:设置成功时返回1。:设置失败时返回0

使用示例

# job 不存在设置成功
redis> EXISTS job
(integer) 0
redis> SETNX job "programmer"
(integer) 1

# job 存在则设置失败
redis> SETNX job "code-farmer"
(integer) 0
redis> GET job
"programmer"

2.1.3 GET - 获取值

GET key

获取字符串key的值。如果key不存在,则返回nil;如果key不是字符串类型,则返回一个错误。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:存在时返回key的值;不存在返回nil;如果key不是字符串类型,返回错误。
# 对不存在的 key 或字符串类型 key 进行 GET
redis> GET db
(nil)
redis> SET db redis
OK
redis> GET db
"redis"

# 对不是字符串类型的 key 进行 GET
redis> DEL db
(integer) 1
redis> LPUSH db redis mongodb mysql
(integer) 3
redis> GET db
(error) ERR Operation against a key holding the wrong kind of value


2.1.4 GETSET - 设置并返回旧值

GETSET key value

设置key的值为value,并返回其旧值。如果key不是字符串类型,则返回一个错误。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:操作成功,返回key旧值。如果key不存在,则返回nil

使用示例:

redis> GETSET db mongodb
(nil)    # 没有旧值,返回 nil

redis> GET db
"mongodb"

redis> GETSET db redis
"mongodb"    # 返回旧值 mongodb

redis> GET db
"redis"


2.2 设置值及有效期

除了使用SET设置key的有效期外,Redis 还提供了SETEXPSETEX两个快捷命令,可以在设置key值的同时指定有效期。

2.2.1 SETEX - 设置key值并指定生存时间(秒)

SETEX key seconds value

设置一个key的值,并以seconds(秒)指定其生存时间。如果key已存在,SETEX将覆盖旧值。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:设置成功时返回OKseconds无效时,返回错误

使用示例

# key 不存在时进行 SETEX
redis> SETEX cache_user_id 60 10086
OK
redis> GET cache_user_id
"10086"
redis> TTL cache_user_id  # 剩余生存时间
(integer) 49

# key 已经存在时,SETEX 会覆盖旧值
redis> SET cd "timeless"
OK
redis> SETEX cd 3000 "goodbye my love"
OK
redis> GET cd
"goodbye my love"
redis> TTL cd
(integer) 2997


2.2.2 PSETEX - 设置key值并指定生存时间(毫秒)

PSETEX key milliseconds value

设置一个key的值,并以milliseconds(毫秒)指定其生存时间。该命令类型与SETEX,但是使用毫秒指定生存时间。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:设置成功时返回OK

使用示例

redis> PSETEX mykey 1000 "Hello"
OK
redis> PTTL mykey
(integer) 999
redis> GET mykey
"Hello"


2.3 子字符串操作

字符串类型支持对子字符串设置或取值,如果需要更新或获取子字符串,可以使用SETRANGEGETRANGE进行操作。

2.3.1 SETRANGE - 设置子字符串

SETRANGE key offset value

使用value覆盖key以偏移量offset开始的字符串。如果key原来储存的字符串长度比偏移量小,那么原字符和偏移量之间的空白将用零字节("\x00")来填充。

偏移量最大可用值是2^29-1(因为 字符串的最为512 M)。

复杂度、返回值:

  • 时间复杂度:O(1)(小字符串)或O(M)(Mvalue的长度)
  • 返回值:修改后字符串的长度。

使用示例

# 对非空字符串进行 SETRANGE
redis> SET greeting "hello world"
OK
redis> SETRANGE greeting 6 "Redis"
(integer) 11
redis> GET greeting
"hello Redis"

# 对空字符串/不存在的 key 进行 SETRANGE
redis> EXISTS empty_string
(integer) 0
redis> SETRANGE empty_string 5 "Redis!"
(integer) 11
redis> GET empty_string
"\x00\x00\x00\x00\x00Redis!"  # 空白处被"\x00"填充


2.3.2 GETRANGE - 获取子字符串

GETRANGE key start end

返回key中字符串值的子字符串,子字符串的截取范围为startend两个偏移量之间(包含startend)。负数偏移量表示从字符串末尾开始计数,-1表示最后一个字符,-2表示倒数第二个,以此类推。

复杂度、返回值:

  • 时间复杂度:O(N)N为要返回的字符串的长度
  • 返回值:获取的子字符串

使用示例

redis> SET greeting "hello, my friend"
OK

# 返回第0-4的字符,包括第4位
redis> GETRANGE greeting 0 4          
"hello"

# 不支持回绕操作
redis> GETRANGE greeting -1 -5        
""
# 负数索引,倒数第3到最后一个
redis> GETRANGE greeting -3 -1 
"end"

# 从第一个到最后一个
redis> GETRANGE greeting 0 -1         
"hello, my friend"

# 取值范围不能超过实际字符串长度范围,超过后会被自动忽略
redis> GETRANGE greeting 0 1008611 
"hello, my friend"


2.4 批量操作

如果需要同时设置或获取多个字符串,可以使用批量操作相关方法。

2.4.1 MSET - 设置多个值

MSET key value [key value ...]

MSET用于同时设置多个key-value对。如果设置的key已存在,则会覆盖原有值

MSET操作具有原子性,所有key设置要么全成功,要么全部失败。

复杂度、返回值:

  • 时间复杂度:O(N)N为要设置的key数量。
  • 返回值:总是返回 OK

使用示例

redis> MSET date "2016.08.14" time "06:00 p.m." weather "sunny"
OK
redis> MGET date time weather
1) "2016.08.14"
2) "06:00 p.m."
3) "sunny"

# 与SET 操作一样,MSET同样会覆盖旧值
redis> SET google "google.hk"
OK
redis> MSET google "google.com"
OK
redis> GET google
"google.com"


2.4.2 MSETNX - key不存在时设置多个值

MSETNX key value [key value ...]

MSETNX用于同时设置多个key-value对,但仅当所有指定的key不存在时才会设置。

复杂度、返回值:

  • 时间复杂度:O(N)N为要设置的key数量。
  • 返回值:所有key设置成功返回 1;设置失败返回0

使用示例

# 对不存在的 key 进行 MSETNX
redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis"
(integer) 1
redis> MGET rmdbs nosql key-value-store
1) "MySQL"
2) "MongoDB"
3) "redis"

# MSET 的给定 key 当中有已存在的 key
redis> MSETNX rmdbs "Sqlite" language "python"
(integer) 0
# 因为 MSET 是原子性操作,language 没有被设置
redis> EXISTS language
(integer) 0
# rmdbs 也没有被修改
redis> GET rmdbs
"MySQL"


2.4.3 MGET - 返回多个key的值

MGET key [key ...]

返回指定的一个或多个key的值。

复杂度、返回值:

  • 时间复杂度:O(N)Nkey数量。
  • 返回值:一个包含key的值的列表

使用示例

redis> SET redis redis.com
OK
redis> SET mongodb mongodb.org
OK
redis> MGET redis mongodb
1) "redis.com"
2) "mongodb.org"
redis> MGET redis mongodb mysql     
1) "redis.com"
2) "mongodb.org"
3) (nil)  # 不存在的 mysql 返回 nil


2.5 自增/自减

Redis 的字符串类型同样可以用于数字值的处理,数字值在Redis 数据库中同样会存储为字符串形式。Redis 提供了用于数字值自增/自减操作的命令,通过这些命令可以实现计数器、限速器等功能。

2.5.1 INCR - 自增

INCR key

key中存储的数字值增加1。如果key不存在,会首先将其初始化为0再执行INCR操作;如果存储的值为非数字,会返回一个错误。

数字值的有效范围为 64 位(bit)有符号数字。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:执行INCR操作后key的值
redis> SET page_view 20
OK
redis> INCR page_view
(integer) 21
redis> GET page_view    
"21"  # 数字值在 Redis 中以字符串的形式保存


2.5.2 INCRBY - 增加指定值

INCRBY key increment

key中存储的数字值增加increment。如果key不存在,会首先将其初始化为0再执行INCRBY操作;如果存储的值为非数字,会返回一个错误。

数字值的有效范围为 64 位(bit)有符号数字。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:增加incrementkey的值

使用示例

# key 存在且是数字值
redis> SET rank 50
OK
redis> INCRBY rank 20
(integer) 70
redis> GET rank
"70"

# key 不存在时
redis> EXISTS counter
(integer) 0
redis> INCRBY counter 30
(integer) 30
redis> GET counter
"30"

# key 不是数字值时
redis> SET book "long long ago..."
OK
redis> INCRBY book 200
(error) ERR value is not an integer or out of range


2.5.3 INCRBYFLOAT - 增加一个浮点值

INCRBYFLOAT key increment

key中存储的数字值增加浮点数increment。如果key不存在,会首先将其初始化为0再执行INCRBYFLOAT操作;如果存储的值为非数字或者所增加的值不能解析为双精度浮点数,会返回一个错误。

key的值和增量increment,都可以使用2.0e73e5等指数形式表示,但是执行INCRBYFLOAT命令之后的值总是以同样的形式储存,即:总是由一个数字,一个可选的小数点和一个任意位的小数部分组成,小数部分尾部的0会被移除,如果能浮点数能表示为整数,会使用整数(如,3.0会被保存为3)。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:增加incrementkey的值

使用示例

# 值、增量都不使用指数
redis> SET mykey 10.50
OK
redis> INCRBYFLOAT mykey 0.1
"10.6"

# 值、增量都是指数符号
redis> SET mykey 314e-2
OK
redis> GET mykey
"314e-2"
# 设置指数形式,执行 INCRBYFLOAT 之后格式会被改成非指数符号
redis> INCRBYFLOAT mykey 0
"3.14"

# INCRBYFLOAT 可用于速数类型
redis> SET mykey 3
OK
redis> INCRBYFLOAT mykey 1.1
"4.1"

# 末尾的 0 会被移除
redis> SET mykey 3.0
OK
redis> GET mykey                                    
"3.0" 
# SET 设置的值小数部分可以是 0,但INCRBYFLOAT 会将没用的 0忽略掉,有需要的话,会将浮点变为整数
redis> INCRBYFLOAT mykey 1.000000000000000000000
"4"
redis> GET mykey
"4"


2.5.4 DECR - 自减

DECR key

key的值减1

如果 key不存在,会被初始化为0再执行DECR操作。

如果key为非数字,那么会返回一个错误。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:执行DECR操作后key的值
# 对存在的数字值 key 进行 DECR
redis> SET failure_times 10
OK
redis> DECR failure_times
(integer) 9

# 对不存在的 key 值进行 DECR
redis> EXISTS count
(integer) 0
redis> DECR count
(integer) -1

# 对存在但不是数值的 key 进行 DECR
redis> SET company YOUR_CODE_SUCKS.LLC
OK
redis> DECR company
(error) ERR value is not an integer or out of range

2.5.5 DECRBY - 自减指定值

DECRBY key decrement

key的值减去decrement

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:减去decrementkey的值
# 对已存在的 key 进行 DECRBY
redis> SET count 100
OK
redis> DECRBY count 20
(integer) 80

# 对不存在的 key 进行DECRBY
redis> EXISTS pages
(integer) 0
redis> DECRBY pages 10
(integer) -10


2.6 位操作

字符串类型还是支持位操作,通过位操作可以实现效率极高的用户上线资料统计功能,参考:REDIS BITMAPS – FAST, EASY, REALTIME METRICS

2.6.1 SETBIT - 位设置

SETBIT key offset value

key所存储的值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于value参数,可以是 01。当key不存在时,自动生成一个新的字符串值。

offset参数的取值范围为大于等于0,小于2^32(bit 映射限制在 512 MB 以内)。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:指定偏移量原来储存的位

使用示例

redis> SETBIT bit 10000 1
(integer) 0
redis> GETBIT bit 10000
(integer) 1
redis> GETBIT bit 100
(integer) 0 # bit 默认被初始化为 0


2.6.2 GETBIT - 获取位

GETBIT key offset

key所储存的字符串值的指定偏移量上的位(bit)。如果offset比字符串值的长度大,或者key不存在时,返回0

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:字符串值指定偏移量上的位(bit)
# 对不存在的 key 或者不存在的 offset 进行 GETBIT, 返回 0
redis> EXISTS bit
(integer) 0
redis> GETBIT bit 10086
(integer) 0

# 对已存在的 offset 进行 GETBIT
redis> SETBIT bit 10086 1
(integer) 0
redis> GETBIT bit 10086
(integer) 1


2.6.3 BITOP - 位运算

BITOP operation destkey key [key ...]

对一个或多个保存二进制位的字符串key进行位元操作,并将结果保存在destkey

参数

  • operation - 表示运算类型,可选值有:AND(与运算)、OR(或运算)、NOT(与运算)、XOR(异或运算)。除NOT只能接收一个key输入外,其它运算都可以接收一个或多个key输入。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:被设置为1的位的数量
redis> SETBIT bits-1 0 1        # bits-1 = 1001
(integer) 0
redis> SETBIT bits-1 3 1
(integer) 0
redis> SETBIT bits-2 0 1        # bits-2 = 1011
(integer) 0
redis> SETBIT bits-2 1 1
(integer) 0
redis> SETBIT bits-2 3 1
(integer) 0
redis> BITOP AND and-result bits-1 bits-2
(integer) 1
redis> GETBIT and-result 0      # and-result = 1001
(integer) 1
redis> GETBIT and-result 1
(integer) 0
redis> GETBIT and-result 2
(integer) 0
redis> GETBIT and-result 3
(integer) 1


2.6.4 BITCOUNT - 高位统计

BITCOUNT key [start] [end]

计算指定字符串中,比特位被设置为1的数量。指定可选参数startend时只统计指定位上的字符,否则统计全部。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:被设置为1的位的数量
redis> BITCOUNT bits
(integer) 0

redis> SETBIT bits 0 1          # 0001
(integer) 0

redis> BITCOUNT bits
(integer) 1

redis> SETBIT bits 3 1          # 1001
(integer) 0

redis> BITCOUNT bits
(integer) 2


2.7 追加、长度判断

2.7.1 APPEND - 追加

APPEND key value

向已存在的名为key字符串的末尾追加value;如果key不存在,执行效果与SET key value相同

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:追加 value 后,key 中字符串的长度
# myphone是一个不存在的 key
redis> APPEND myphone "nokia"
(integer) 5                         # 字符长度

# 对已存在的字符串进行 APPEND
redis> APPEND myphone " - 1110"     # 长度从 5 个字符增加到 12 个字符
(integer) 12

redis> GET myphone
"nokia - 1110"


2.7.2 STRLEN - 字符串长度

STRLEN key

返回key的值的长度。如果key的值不是字符串,则返回一个错误。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:字符串的长度。如果key不存在返回0

使用示例

redis> SET mykey "Hello world"
OK
redis> STRLEN mykey
(integer) 11

# 不存在的 key 长度为 0
redis> STRLEN nonexisting
(integer) 0