# 2.2 针对字符串的命令

Redis是基于"键值对"的NoSQL.而此处的"string"是指"键值对"中的"值"是以"string"形式存储数据的.

## 2.2.1 读写字符串的set和get命令

设置字符串对象的语法:

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

其中:

* `key`: 键名.若对应的key中已经有值,那么再次执行`SET`命令时会用新的value替换旧的value
* `value`: **字符串类型的**值
* `EX/PX`: 设置生存周期.其中`EX`的单位为秒;`PX`的单位为毫秒
* `NX`: 当`key`不存在时才进行设置值的操作,若key存在则该命令不执行
* `XX`: 与`NX`相反,表示当key存在时才进行操作
* `KEEPTTL`: 在设置新的键值对时,保持原有的TTL(Time To Live,生存时间)不变.
  * 该选项为Redis 6.0新增选项.当使用`SET`命令对一个已经存在的key设置value时,若该key已经存在生存周期,则新的`SET`命令会移除这个生存周期.此时加上`KEEPTTL`选项,则表示保持该key原有的生存周期不变.

```
127.0.0.1:6379> SET name foo ex 5
OK
127.0.0.1:6379> GET name bar keepttl
OK
127.0.0.1:6379> SET name
"bar"
```

需求:工号为001的员工姓名为Mike,这条数据是存储在Emp表里的,但是每次查询该数据时需要读表,这会影响数据库的性能,所以需要在Redis里缓存该条数据.

设置了错误的员工姓名:

```
127.0.0.1:6379> SET 001 'Mary'
OK
```

注意:此处的`'Mary'`带有`'`,表示设置的值类型为字符串

此处的返回值`OK`表示设置成功

尝试将姓名修改为Mike:

```
127.0.0.1:6379> SET 001 'Mike' NX
(nil)
```

此处的返回值`nil`表示设置不成功

```
127.0.0.1:6379> SETNX 001 'Mike'
(integer) 0
```

此处的`setNX key value`和`set key value NX`是等价的.返回值`(integer) 0`同样表示设置不成功

查看`key`为`001`的值:

```
127.0.0.1:6379> GET 001
"Mary"
```

将`key`为`001`的值替换为Mike:

```
127.0.0.1:6379> SET 001 'Mike'
OK
```

查看结果:

```
127.0.0.1:6379> GET 001
"Mike"
```

例:将工号为002、姓名为Tom的数据写入Redis:

确认key是否存在:

```
127.0.0.1:6379> GET 002
(nil)
```

此处返回值`nil`表示没有找到key为`002`的数据

当key为`002`的数据存在时设置其值为`'Tom'`:

```
127.0.0.1:6379> SET 002 'Tom' XX
(nil)
```

此处由于key为`002`的数据不存在,故不进行操作,该`SET`命令返回值为`nil`表示没有进行操作

设置key为002的value为`'Tom'`,生存周期为10ms:

```
127.0.0.1:6379> SET 002 'Tom' PX 10
OK
```

10ms后获取key为002的value:

```
127.0.0.1:6379> GET 002
(nil)
```

此处返回`nil`表示没有获取到对应的值

设置key为002的value为`'Tom'`,生存周期为12分钟:

```
127.0.0.1:6379> SET 002 'Tom' EX 60*12
(error) ERR value is not an integer or out of range
```

报错原因:生存周期必须为一个数值,不能是一个表达式

```
127.0.0.1:6379> SET 002 'Tom' EX 720
OK
```

可以看到,值设置成功.

查看结果:

```
127.0.0.1:6379> GET 002
"Tom"
```

## 2.2.2 设置和获取多个字符串的命令

* `MSET`:设置多个字符串
  * 语法:`MSET key value [key value]`
* `MGET`:获取多个字符串
  * 语法:`MGET key [key]`

注意:`MSET`、`MGET`命令不包含`NX`、`XX`、`EX`、`PX`等参数

例:

同时对`003`和`004`这2个key设置string类型的值:

```
127.0.0.1:6379> MSET 003 'Peter' 004 Mary EX 10
OK
```

注:此处虽然使用`EX`参数设置了生命周期,但实际上这个生命周期不会生效

注:可以看到,字符串可以用`"`或`'`包含,也可以不包含.效果相同

10秒后使用`MGET`命令获取key为003和004的value:

```
127.0.0.1:6379> MGET 003 004
1) "Peter"
2) "Mary"
```

可以看到,虽然使用`MSET`命令设置了生命周期为10s,但并未生效.10s后依旧能通过key取到value

使用`MSET`指令时同时指定`NX`或`XX`参数:

```
127.0.0.1:6379> MSET 003 "Peter" 006 'JohnSon' NX
(error) ERR wrong number of arguments for MSET
```

```
127.0.0.1:6379> MSET 003 "Peter" 006 'JohnSon' XX
(error) ERR wrong number of arguments for MSET
```

可以看到,`MSET`命令不支持`NX`和`XX`参数

同时对`007`和`008`这2个key设置string类型的值:

```
127.0.0.1:6379> MSET 007 "John" 008 'Tim' PX 10
OK
```

注:此处虽然使用`PX`参数设置了生命周期,但实际上这个生命周期不会生效

10ms后使用`MGET`命令获取key为`007`和`008`的value:

```
127.0.0.1:6379> MGET 007 008
1) "John"
2) "Tim"
```

可以看到,虽然使用`MSET`命令时通过`PX`选项设置了生命周期为10ms,但并未生效.10ms后依旧能通过key取到value.**即:`PX`和`EX`参数不会生效**

## 2.2.3 对值进行增量和减量操作

* `INCR key`:对key所对应的**数字类型值**进行加1操作
* `DECR key`:对key所对应的**数字类型值**进行减1操作
* `INCRBY key increment`:对key对应的值进行加increment的操作
* `DECRBY key decrement`:对key对应的值进行减decrement的操作

```
127.0.0.1:6379> GET visit
(nil)
```

对visit变量进行加1操作:

```
127.0.0.1:6379> INCR visit
(integer) 1
```

对visit进行加10操作:

```
127.0.0.1:6379> INCRBY visit 10
(integer) 11
```

对visit进行减1操作:

```
127.0.0.1:6379> DECR visit
(integer) 10
```

对visit进行减5操作:

```
127.0.0.1:6379> DECRBY visit 5
(integer) 5
```

```
127.0.0.1:6379> GET visit
"5"
```

将`INCR`命令和`DECR`命令作用在字符串类型上:

```
127.0.0.1:6379> SET visitPersion 'Peter'
OK
127.0.0.1:6379> INCR visitPersion
(error) ERR value is not an integer or out of range
127.0.0.1:6379> DECR visitPersion
(error) ERR value is not an integer or out of range
```

可以看到,**将`INCR`命令和`DECR`命令作用在字符串类型上会报错**.

## 2.2.4 通过getset命令设置新值

`GETSET`:若key对应的值存在,则用给定的值覆盖旧的值,同时返回旧的值;若key对应的值不存在,也会设置值,但会返回`nil`.语法:`GETSET key value`

```
127.0.0.1:6379> GETSET 009 'Alex'
(nil)
```

```
127.0.0.1:6379> GET 009
"Alex"
```

```
127.0.0.1:6379> GETSET 009 'Frank'
"Alex"
```

```
127.0.0.1:6379> GET 009
"Frank"
```

## 2.2.5 针对字符串的其他操作

* `GETRANGE`:
  * 语法:`GETRANGE key start end`
  * 功能:获取key的子字符串.返回key对应的值从start位置开始到end位置为止的子字符串.其中位置的计算从0开始.返回的子字符串包含start位置和end位置

例:

```
127.0.0.1:6379> SET tel 021-12345678
OK
```

```
127.0.0.1:6379> GETRANGE tel 4 12
"12345678"
```

* `SETRANGE`:
  * 语法:`SETRANGE key offset value`
  * 功能:从offset位置开始,把值替换为value.该命令的返回值是字符串的长度

例:

```
127.0.0.1:6379> GET tel
"021-12345678"
```

```
127.0.0.1:6379> SETRANGE tel 4 87654321
(integer) 12
```

```
127.0.0.1:6379> GET tel
"021-87654321"
```

注:若offset超出了字符串的长度,则会用空白字符(`\x00`)进行填充,填充至到达指定的偏移量后再进行替换.这个过程可能会导致字符串长度的增加.

```
127.0.0.1:6379> SETRANGE tel 15 -2468
(integer) 20
```

```
127.0.0.1:6379> GET tel
"021-87654321\x00\x00\x00-2468"
```

* `STRLEN`:
  * 语法:`STRLEN key`
  * 功能:返回字符串的长度

```
127.0.0.1:6379> STRLEN tel
(integer) 20
```

* `APPEND`
  * 语法:`APPEND key value`
  * 功能:将value追加到原值的末尾.该命令的返回值是追加后的字符串的长度

```
127.0.0.1:6379> GET tel
"021-87654321\x00\x00\x00-2468"
```

```
127.0.0.1:6379> GET tel
"021-87654321\x00\x00\x00-2468-3579"
```

注:若对一个不存在的key使用`APPEND`指令,则等价于`SET`指令

```
127.0.0.1:6379> GET keym
(nil)
```

```
127.0.0.1:6379> APPEND keym content
(integer) 7
```

```
127.0.0.1:6379> GET keym
"content"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://redis.sai.show/di-2-zhang-shi-jian-redis-de-ji-ben-shu-ju-lei-xing/2.2-zhen-dui-zi-fu-chuan-de-ming-ling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
