# 3.1 键操作命令

## 3.1.1 用`EXISTS`命令判断键是否存在

* `EXISTS`
  * 语法:`EXISTS key`
  * 功能:判断指定的key是否存在.存在返回1,否则返回0

例:

设置一个名为name的key:

```
127.0.0.1:6379> SET name "Peter"
OK
```

判断该key是否存在:

```
127.0.0.1:6379> EXISTS name
(integer) 1
```

判断一个不存在的key:

```
127.0.0.1:6379> EXISTS grade
(integer) 0
```

## 3.1.2 用`KEYS`命令查找键

* `KEYS`
  * 语法:`KEYS pattern`
  * 功能:用通配符或正则表达式来查找指定模式的键

例:

添加3个以`0`开头的键值对:

```
127.0.0.1:6379> SET 001 Peter
OK
127.0.0.1:6379> SET 002 Mike
OK
127.0.0.1:6379> SET 003 Tim
OK
```

查找所有以`0`开头的key:

```
127.0.0.1:6379> KEYS 0*
1) "001"
2) "003"
3) "002"
```

查找以`n`开头,`n`后边有1个任意字符,该字符后边以`me`结尾的key:

```
127.0.0.1:6379> KEYS n?me
1) "name"
```

查找所有的key:

```
127.0.0.1:6379> KEYS *
1) "001"
2) "name"
3) "003"
4) "002"
```

## 3.1.3 用`SCAN`命令查找键

* `SCAN`
  * 语法:`SCAN cursor [MATCH pattern] [COUNT count]`.其中:
    * cursor:游标,游标起始值一般为0
    * pattern:指定匹配模式
    * count:`COUNT`选项并不是一个硬性约束,而是一个提示或者建议,表示你希望每次迭代返回的大致结果数量.但实际返回的键数量可能会有所不同.确切的讲,`COUNT`提供了Redis应该在每次迭代中检查的桶(buckets)数量.担着不表示返回的结果数量一定与`COUNT`的值相匹配
  * 功能:`SCAN`返回一个包含两个元素的数组,第一个元素是用于进行下一次迭代的新游标, 而第二个元素则是一个数组,这个数组中包含了所有被迭代的元素

原因如下:

1. Redis内部使用哈希表来存储键,而哈希表又基于桶(bucket)来工作
2. 当执行`SCAN`命令时,Redis会尝试在每次迭代中检查大约`COUNT`数量的桶
3. 某个桶可能为空,也可能包含多个键
4. 当使用`MATCH`选项时,只有匹配该模式的键会被返回.因此,即使一个桶中有多个键,也可能只有一部分键与给定模式匹配

因此,当你指定`COUNT 1`时,Redis会尝试检查大约1个桶的内容.但根据哈希表的实际状态和`MATCH`模式,返回的键数量可能会多于或少于`COUNT`的值

总的来说,应该将`COUNT`视为一个估计或建议,而不是一个确切的限制.如果你需要准确控制返回的键数量,你可能需要在客户端进行进一步的处理

例:

查看键名以0开头的所有键:

```
127.0.0.1:6379> KEYS 0*
 1) "001"
 2) "019"
 3) "014"
 4) "004"
 5) "020"
 6) "018"
 7) "006"
 8) "003"
 9) "013"
10) "015"
11) "011"
12) "008"
13) "016"
14) "005"
15) "009"
16) "002"
17) "007"
18) "012"
19) "010"
20) "017"
```

可以看到,以0开头的键共有20个.即001 - 020

使用`SCAN`命令迭代获取key:

```
127.0.0.1:6379> SCAN 20 MATCH 0* COUNT 1
1) "28"
2) 1) "005"
   2) "009"
```

可以看到,即使指定`COUNT 1`,返回的key也可能不止1个.

```
127.0.0.1:6379> SCAN 28 MATCH 0* COUNT 1
1) "2"
2) 1) "017"
```

```
127.0.0.1:6379> SCAN 2 MATCH 0* COUNT 1
1) "18"
2) 1) "019"
   2) "014"
```

```
127.0.0.1:6379> SCAN 18 MATCH 0* COUNT 1
1) "22"
2) 1) "011"
```

```
127.0.0.1:6379> SCAN 22 MATCH 0* COUNT 1
1) "14"
2) (empty array)
```

可以看到,在迭代的过程中是有可能返回空数组的

```
127.0.0.1:6379> SCAN 14 MATCH 0* COUNT 1
1) "5"
2) 1) "012"
```

```
127.0.0.1:6379> SCAN 5 MATCH 0* COUNT 1
1) "21"
2) 1) "015"
```

```
127.0.0.1:6379> SCAN 21 MATCH 0* COUNT 1
1) "13"
2) 1) "007"
```

```
127.0.0.1:6379> SCAN 13 MATCH 0* COUNT 1
1) "19"
2) 1) "004"
```

```
127.0.0.1:6379> SCAN 19 MATCH 0* COUNT 1
1) "11"
2) 1) "002"
```

```
127.0.0.1:6379> SCAN 11 MATCH 0* COUNT 1
1) "27"
2) 1) "016"
```

```
127.0.0.1:6379> SCAN 27 MATCH 0* COUNT 1
1) "7"
2) 1) "010"
```

```
127.0.0.1:6379> SCAN 7 MATCH 0* COUNT 1
1) "23"
2) 1) "008"
```

```
127.0.0.1:6379> SCAN 23 MATCH 0* COUNT 1
1) "0"
2) (empty array)
```

遍历结束的标志是cursor再次变为0

注意:

* `KEYS`命令以阻塞的方式来查找并返回键.因此当待查找的键数量很多时,耗时会较长,且在这段时间内无法执行其他命令(Redis是单线程的)
* `SCAN`命令以非阻塞的方式查找并返回键.换言之,在大部分场景下`SCAN`命令能替代`KEYS`命令.**如果待查找的键个数比较少,那么用`KEYS`命令尚可,否则建议使用`SCAN`命令**

## 3.1.4 重命名键

* `RENAME`
  * 语法:`RENAME key newkey`
  * 功能:若旧键名不存在,则返回错误;若newkey已存在,则用key对应的值覆盖newkey对应的值
* `RENAMENX`
  * 语法:`RENAMENX key newkey`
  * 功能:若旧键名不存在,则返回错误;若newkey已存在,则返回0,不执行重命名命令

例:使用`RENAME`重命名键

设置键:

```
127.0.0.1:6379> SET visitPerson Peter
OK
```

重命名键:

```
127.0.0.1:6379> RENAME visitPerson VIPPerson
OK
```

查看旧的key和新的key的存在情况:

```
127.0.0.1:6379> EXISTS visitPerson
(integer) 0
```

可以看到,旧的key已经不存在了

```
127.0.0.1:6379> EXISTS VIPPerson
(integer) 1
127.0.0.1:6379> GET VIPPerson
"Peter"
```

新的key已存在且值为旧的key对应的值

例:使用`RENAME`覆盖key值

删除并重新设置2个键:

```
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> SET visitPerson Peter
OK
127.0.0.1:6379> SET VIPPerson Mike
OK
127.0.0.1:6379> GET visitPerson
"Peter"
127.0.0.1:6379> GET VIPPerson
"Mike"
```

重命名键visitPerson为VIPPerson:

```
127.0.0.1:6379> RENAME visitPerson VIPPerson
OK
```

查看覆盖后的VIPPerson:

```
127.0.0.1:6379> EXISTS VIPPerson
(integer) 1
127.0.0.1:6379> GET VIPPerson
"Peter"
```

可以看到,覆盖操作后,VIPPerson的值即为覆盖操作前visitPerson的值

例:使用`RENAME`重命名一个不存在的键

```
127.0.0.1:6379> RENAME notExist VipPerson
(error) ERR no such key
```

例:使用`RENAMENX`重命名一个键

设置一个键:

```
127.0.0.1:6379> SET visitPerson Peter
OK
```

使用`RENAMENX`重命名键:

```
127.0.0.1:6379> RENAMENX visitPerson VIPPerson
(integer) 1
```

查看重命名结果:

```
127.0.0.1:6379> EXISTS visitPerson
(integer) 0
127.0.0.1:6379> EXISTS VIPPerson
(integer) 1
127.0.0.1:6379> GET VIPPerson
"Peter"
```

使用`RENAMENX`重命名一个已有的键名:

设置2个键:

```
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> SET visitPerson Peter
OK
127.0.0.1:6379> SET VIPPerson Mike
OK
```

使用`RENAMENX`重命名:

```
127.0.0.1:6379> RENAMENX visitPerson VIPPerson
(integer) 0
127.0.0.1:6379> GET visitPerson
"Peter"
127.0.0.1:6379> GET VIPPerson
"Mike"
```

可以看到,重命名操作没有生效

使用`RENAMENX`命令重命名一个不存在的键:

```
127.0.0.1:6379> EXISTS notExist
(integer) 0
```

```
127.0.0.1:6379> RENAMENX notExist existed
(error) ERR no such key
```

可以看到,使用`RENAMENX`重命名一个不存在的键则报错

3.1.5 用`DEL`命令删除键

* `DEL`
  * 语法:`DEL key [key ...]`
  * 功能:删除键值对.该命令返回删除的键值对个数

例:

设置一个键:

```
127.0.0.1:6379> SET name Peter
OK
```

删除多个键:

```
127.0.0.1:6379> EXISTS notExist
(integer) 0
```

可以看到,键`notExist`是不存在的

```
127.0.0.1:6379> DEL name notExist
(integer) 1
```

可以看到,返回值表示删除了1个键

删除一个不存在的键:

```
127.0.0.1:6379> DEL notExist
(integer) 0
```

可以看到,返回值为0,表示删除操作失败

## 3.1.6 关于键生存时间的命令

### 3.1.6.1 查看键的生存周期

* `PTTL`
  * 语法:`PTTL key`
  * 功能:返回指定key的生存周期,单位:毫秒.若key不存在,则返回-2;若key存在但未设置生存周期
* `TTL`
  * 语法:`TTL key`
  * 功能:返回指定key的生存周期,单位:秒.若key不存在,则返回-2;若key存在但未设置生存周期

例:

设置一个生存周期为300秒的key

```
127.0.0.1:6379> SET val 100 EX 300
OK
```

查看该key的生存周期:

```
127.0.0.1:6379> PTTL val
(integer) 297805
127.0.0.1:6379> TTL val
(integer) 295
```

设置一个无生存周期的key:

```
127.0.0.1:6379> DEL val
(integer) 1
127.0.0.1:6379> SET val 100
OK
```

查看无生存周期key的生存周期:

```
127.0.0.1:6379> PTTL val
(integer) -1
127.0.0.1:6379> TTL val
(integer) -1
```

查看一个不存在的key的生存周期:

```
127.0.0.1:6379> EXISTS notExist
(integer) 0
```

```
127.0.0.1:6379> PTTL notExist
(integer) -2
127.0.0.1:6379> TTL notExist
(integer) -2
```

### 3.1.6.2 设置键的生存周期

* `EXPIRE`
  * 语法:`EXPIRE key seconds`
  * 功能:以秒为单位设置一个key的生存周期.设置成功返回1,否则返回0
* `PEXPIRE`
  * 语法:`PEXPIRE key milliseconds`
  * 功能:以毫秒为单位设置一个key的生存周期.设置成功返回1,否则返回0

例:

设置一个无生存周期的key:

```
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> SET val 100
OK
```

设置该key的生存周期为200秒:

```
127.0.0.1:6379> EXPIRE val 200
(integer) 1
```

查看该key的生存周期:

```
127.0.0.1:6379> TTL val
(integer) 173
```

设置该key的生存周期为20000毫秒:

```
127.0.0.1:6379> PEXPIRE val 20000
(integer) 1
```

查看该key的生存周期:

```
127.0.0.1:6379> PTTL val
(integer) 16070
```

给一个不存在的key设置生存周期:

```
127.0.0.1:6379> EXPIRE notExist 10
(integer) 0
127.0.0.1:6379> PEXPIRE notExist 1000
(integer) 0
```

### 3.1.6.3 删除键的生存周期

* `PERSIST`
  * 语法:`PERSIST key`
  * 功能:删除键的生存周期,即该键永不过期.删除操作成功则返回1,否则返回0

例:

设置一个生存周期为200秒的键:

```
127.0.0.1:6379> SET val 100 EX 200
OK
```

查看该key的生存周期:

```
127.0.0.1:6379> TTL val
(integer) 179
```

删除该key的生存周期:

```
127.0.0.1:6379> PERSIST val
(integer) 1
```

查看该key的生存周期:

```
127.0.0.1:6379> TTL val
(integer) -1
```

删除一个不存在的key的生存周期:

```
127.0.0.1:6379> EXISTS notExist
(integer) 0
127.0.0.1:6379> PERSIST notExist
(integer) 0
```
