Files
Cloud-book/数据库/Redis_2025/04_Redis基本命令.md
2025-08-27 17:10:05 +08:00

590 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Redis 基本命令
Redis 提供了丰富的命令来管理键、数据库、事务和脚本。掌握这些基本命令是高效使用 Redis 的基础。
## 键操作命令
### 键的命名规范
良好的键命名规范是 Redis 应用的重要基础,有助于提高可维护性和性能。
**推荐的命名规范:**
1. **使用冒号分隔层级**
```shell
user:1001:profile
product:category:electronics
cache:query:user_list
session:web:abc123
```
2. **使用有意义的前缀**
```shell
# 按功能分类
cache:* # 缓存数据
session:* # 会话数据
config:* # 配置信息
temp:* # 临时数据
# 按业务分类
user:* # 用户相关
order:* # 订单相关
product:* # 商品相关
```
3. **避免特殊字符**
```shell
# 推荐
user:1001:name
article:2023:01:15
# 不推荐
user 1001 name
article@2023#01#15
```
4. **保持一致性**
```shell
# 统一使用小写
user:profile:name
user:profile:email
# 统一日期格式
log:2024:01:15
report:2024:01:15
```
### 键的查询和遍历
**基本查询命令**
```shell
# 检查键是否存在
# 用法EXISTS key [key ...]
EXISTS user:1001
EXISTS user:1001 user:1002 user:1003 # 返回存在的键数量
# 获取键的类型
# 用法TYPE key
TYPE user:1001 # 返回 hash
TYPE user:tags # 返回 set
TYPE message_queue # 返回 list
# 获取键的编码方式
# 用法OBJECT ENCODING key
OBJECT ENCODING user:1001
OBJECT ENCODING counter
# 获取键的空闲时间(秒)
# 用法OBJECT IDLETIME key
# 注意:返回值为键的空闲时间,单位为秒。
OBJECT IDLETIME user:1001
# 获取键的引用计数
# 用法OBJECT REFCOUNT key
# 注意:返回值为键的引用计数,单位为秒。
OBJECT REFCOUNT user:1001
```
**模式匹配查询**
```shell
# 查找匹配模式的键(谨慎使用)
# 用法KEYS pattern
KEYS user:* # 查找所有用户相关的键
KEYS cache:* # 查找所有缓存键
KEYS *:1001:* # 查找包含1001的键
KEYS user:100? # ?匹配单个字符
KEYS user:[12]* # []匹配字符集合
# 更安全的遍历方式(推荐)
# 用法SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
SCAN 0 MATCH user:* COUNT 10
SCAN 0 MATCH cache:* COUNT 20
SCAN 0 TYPE string COUNT 10
# 示例:安全遍历所有用户键
redis-cli --scan --pattern "user:*"
```
**随机获取键**
```shell
# 随机返回一个键
# 用法RANDOMKEY
# 示例:随机获取键进行采样
RANDOMKEY
RANDOMKEY
RANDOMKEY
```
### 键的过期设置
Redis 支持为键设置过期时间,这是内存管理和缓存实现的重要功能。
**设置过期时间**
```shell
# 设置键的过期时间(秒)
# 用法EXPIRE key seconds
EXPIRE user:1001 3600 # 1小时后过期
EXPIRE temp_data 300 # 5分钟后过期
# 设置键的过期时间(毫秒)
# 用法PEXPIRE key milliseconds
PEXPIRE temp_data 30000 # 30秒后过期
# 设置键的过期时间戳(秒)
# 用法EXPIREAT key timestamp
EXPIREAT temp_data 1705123200 # 指定时间戳过期
# 设置键的过期时间戳(毫秒)
# 用法PEXPIREAT key milliseconds-timestamp
PEXPIREAT temp_data 1705123200000
# 创建键时同时设置过期时间
# 用法SETEX key seconds value
SETEX key seconds value
SETEX session:abc123 3600 "user_data"
# 创建键时同时设置过期时间(毫秒)
# 用法PSETEX key milliseconds value
PSETEX session:def456 3600000 "user_data"
```
**查询过期时间**
```shell
# 获取键的剩余生存时间(秒)
# 用法TTL key
TTL session:abc123 # 返回剩余秒数,-1表示永不过期-2表示不存在
# 获取键的剩余生存时间(毫秒)
# 用法PTTL key
PTTL session:abc123 # 返回剩余毫秒数
# 示例:检查多个键的过期时间
SETEX key1 100 "value1"
SETEX key2 200 "value2"
SET key3 "value3" # 永不过期
TTL key1
TTL key2
TTL key3
```
**移除过期时间**
```shell
# 移除键的过期时间,使其永久存在
# 用法PERSIST key
PERSIST session:abc123
SETEX temp_key 300 "临时数据"
TTL temp_key # 查看过期时间
PERSIST temp_key # 移除过期时间
TTL temp_key # 返回-1表示永不过期
```
### 键的删除和重命名
**删除键**
```shell
# 删除一个或多个键
# 用法DEL key [key ...]
DEL user:1001
DEL cache:query1 cache:query2 cache:query3
# 异步删除键(适用于大键)
# 用法UNLINK key [key ...]
UNLINK large_list large_set large_hash
# 删除所有键(危险操作)
FLUSHDB # 删除当前数据库所有键
FLUSHALL # 删除所有数据库所有键
```
**重命名键**
```shell
# 重命名键
# 用法RENAME key newkey
RENAME user:1001 user:1002
SET old_name "value"
RENAME old_name new_name
GET new_name
# 仅当新键不存在时重命名
# 用法RENAMENX key newkey
RENAMENX source_key target_key # 成功返回1
RENAMENX source_key target_key # 失败返回0target_key已存在
```
## 数据库操作
### 多数据库概念
Redis 支持多个数据库默认有16个数据库编号0-15可以通过配置文件修改数量。
**数据库特点:**
- 每个数据库都是独立的键空间
- 不同数据库间的键名可以相同
- 默认连接到数据库0
- 数据库间不支持关联查询
**使用场景:**
- 区分不同环境(开发、测试、生产)
- 分离不同类型的数据
- 临时数据隔离
### 数据库切换
```shell
# 切换到指定数据库
# 用法SELECT index
SELECT 0 # 切换到数据库0
SELECT 1 # 切换到数据库1
SELECT 15 # 切换到数据库15
# 示例:在不同数据库中存储数据
SELECT 0
SET app:env "production"
SET app:version "1.0.0"
SELECT 1
SET app:env "development"
SET app:version "1.1.0-dev"
SELECT 2
SET temp:data "临时测试数据"
# 验证数据隔离
SELECT 0
GET app:env # 返回 "production"
SELECT 1
GET app:env # 返回 "development"
```
### 数据库清空
```shell
# 清空当前数据库
FLUSHDB
# 异步清空当前数据库
FLUSHDB ASYNC
# 清空所有数据库
FLUSHALL
# 异步清空所有数据库
FLUSHALL ASYNC
# 示例:安全的数据库清理
SELECT 15 # 切换到测试数据库
SET test:key "test_value"
DBSIZE # 查看键数量
FLUSHDB # 清空测试数据库
DBSIZE # 确认清空结果
```
### 数据库信息查看
```shell
# 获取当前数据库键的数量
DBSIZE
# 获取服务器信息
INFO [section]
INFO # 获取所有信息
INFO server # 服务器信息
INFO clients # 客户端信息
INFO memory # 内存信息
INFO keyspace # 键空间信息
# 获取配置信息
CONFIG GET parameter
CONFIG GET databases # 查看数据库数量配置
CONFIG GET maxmemory # 查看最大内存配置
# 示例:查看各数据库使用情况
INFO keyspace
# 输出示例:
# db0:keys=100,expires=10,avg_ttl=3600000
# db1:keys=50,expires=5,avg_ttl=1800000
```
## 事务操作
### 事务的概念
Redis 事务是一组命令的集合,这些命令会被顺序执行,具有以下特点:
**事务特性:**
- **原子性**:事务中的命令要么全部执行,要么全部不执行
- **一致性**:事务执行前后,数据保持一致状态
- **隔离性**:事务执行过程中不会被其他命令干扰
- **持久性**:事务执行结果会被持久化(如果启用了持久化)
**Redis 事务限制:**
- 不支持回滚
- 命令错误不会影响其他命令执行
- 不支持嵌套事务
### MULTI/EXEC 命令
**基本事务操作**
```shell
# 开始事务
MULTI
# 添加命令到事务队列
SET account:1001:balance 1000
SET account:1002:balance 500
DECRBY account:1001:balance 100
INCRBY account:1002:balance 100
# 执行事务
EXEC
# 取消事务
# DISCARD
```
**完整事务示例**
```shell
# 银行转账事务示例
MULTI
GET account:1001:balance # 检查余额
DECRBY account:1001:balance 100
INCRBY account:1002:balance 100
SET transfer:log "1001->1002:100"
EXEC
# 批量用户创建事务
MULTI
HMSET user:2001 name "用户A" email "usera@example.com" status "active"
HMSET user:2002 name "用户B" email "userb@example.com" status "active"
SADD active_users "user:2001" "user:2002"
INCR total_users
EXEC
```
**事务错误处理**
```shell
# 语法错误示例(事务不会执行)
MULTI
SET key1 value1
INVALID_COMMAND # 语法错误
SET key2 value2
EXEC # 返回错误,事务不执行
# 运行时错误示例(其他命令仍会执行)
MULTI
SET string_key "hello"
LPUSH string_key "world" # 类型错误,但不影响其他命令
SET another_key "value"
EXEC # 部分命令执行成功
```
### WATCH 命令
WATCH 命令用于实现乐观锁,监视键的变化。
**基本用法**
```shell
# 监视键
WATCH key [key ...]
WATCH account:1001:balance account:1002:balance
# 开始事务
MULTI
DECRBY account:1001:balance 100
INCRBY account:1002:balance 100
EXEC # 如果被监视的键发生变化,事务不会执行
# 取消监视
UNWATCH
```
**乐观锁实现**
```shell
# 实现安全的计数器增加
WATCH counter
val=$(redis-cli GET counter)
if [ "$val" -lt 100 ]; then
redis-cli MULTI
redis-cli INCR counter
redis-cli EXEC
else
redis-cli UNWATCH
echo "计数器已达到上限"
fi
```
**复杂事务示例**
```shell
# 库存扣减事务(防止超卖)
WATCH product:1001:stock
stock=$(redis-cli GET product:1001:stock)
if [ "$stock" -ge 1 ]; then
redis-cli MULTI
redis-cli DECR product:1001:stock
redis-cli LPUSH order:queue "order:$(date +%s)"
redis-cli INCR sales:total
result=$(redis-cli EXEC)
if [ "$result" != "" ]; then
echo "购买成功"
else
echo "购买失败,请重试"
fi
else
redis-cli UNWATCH
echo "库存不足"
fi
```
### 事务的特性和限制
**事务特性验证**
```shell
# 原子性验证
SET test:atomic "initial"
MULTI
SET test:atomic "step1"
SET test:atomic "step2"
SET test:atomic "final"
EXEC
GET test:atomic # 返回 "final"
# 隔离性验证(在事务执行期间,其他客户端的命令不会干扰)
# 客户端1
MULTI
SET test:isolation "value1"
# 暂停不执行EXEC
# 客户端2
SET test:isolation "value2" # 这个命令会立即执行
# 客户端1继续
EXEC
GET test:isolation # 返回 "value1"事务中的值覆盖了客户端2的修改
```
**事务限制示例**
```shell
# 无回滚特性
SET balance 1000
MULTI
DECRBY balance 100 # 成功
LPUSH balance "error" # 类型错误,但不影响前面的命令
DECRBY balance 50 # 成功
EXEC
GET balance # 返回 "850"(前面和后面的命令都执行了)
# 条件执行限制Redis事务不支持if-else逻辑
# 需要在应用层实现条件判断
balance=$(redis-cli GET account:balance)
if [ "$balance" -gt 100 ]; then
redis-cli MULTI
redis-cli DECRBY account:balance 100
redis-cli SET last:transaction "withdraw:100"
redis-cli EXEC
else
echo "余额不足"
fi
```
## 脚本操作
### Lua 脚本简介
Redis 内嵌了 Lua 解释器,支持执行 Lua 脚本。Lua 脚本的优势:
**主要优势:**
- **原子性**:脚本执行过程中不会被其他命令干扰
- **减少网络开销**:多个命令在服务器端执行
- **复杂逻辑**:支持条件判断、循环等复杂逻辑
- **性能优化**:避免多次网络往返
**使用场景:**
- 复杂的原子操作
- 条件判断和循环
- 批量数据处理
- 限流算法实现
- 分布式锁
### EVAL 和 EVALSHA 命令
**EVAL 命令基本用法**
```shell
# EVAL script numkeys key [key ...] arg [arg ...]
# script: Lua脚本
# numkeys: 键的数量
# key: 键名
# arg: 参数
# 简单示例:设置键值并返回
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 mykey myvalue
# 获取并增加计数器
EVAL "local val = redis.call('GET', KEYS[1]) or 0; return redis.call('INCR', KEYS[1])" 1 counter
# 条件设置(仅当键不存在时设置)
EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then return redis.call('SET', KEYS[1], ARGV[1]) else return nil end" 1 newkey newvalue
```
**EVALSHA 命令**
```shell
# 加载脚本并获取SHA1值
SCRIPT LOAD "return redis.call('GET', KEYS[1])"
# 返回:"6b1bf486c81ceb7edf3c093f4c48582e38c0e791"
# 使用SHA1值执行脚本
EVALSHA 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 1 mykey
# 检查脚本是否存在
SCRIPT EXISTS sha1 [sha1 ...]
SCRIPT EXISTS 6b1bf486c81ceb7edf3c093f4c48582e38c0e791
# 清除脚本缓存
SCRIPT FLUSH
# 杀死正在执行的脚本
SCRIPT KILL
```
### 脚本缓存
Redis 会缓存已执行的脚本,提高重复执行的性能。
```shell
# 预加载常用脚本
incr_script_sha=$(redis-cli SCRIPT LOAD "return redis.call('INCR', KEYS[1])")
echo "增加计数器脚本SHA: $incr_script_sha"
# 使用缓存的脚本
redis-cli EVALSHA $incr_script_sha 1 my_counter
redis-cli EVALSHA $incr_script_sha 1 my_counter
redis-cli EVALSHA $incr_script_sha 1 my_counter
# 检查脚本缓存状态
redis-cli SCRIPT EXISTS $incr_script_sha
# 获取脚本缓存统计
redis-cli INFO memory | grep script
```
## 实践操作