# 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
```


---

# 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-3-zhang-shi-jian-redis-de-chang-yong-ming-ling/3.1-jian-cao-zuo-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.
