# Lua 脚本

URL: https://caijiao.org/redis/05-advanced/03-lua
Source: docs/redis/05-advanced/03-lua.md
Description: Redis Lua 脚本通过原子性执行多个命令，可以在一个脚本内组合多个操作，确保数据一致性并减少客户端与服务器的通信次数。

Redis 提供了原生支持 Lua 脚本的功能，可以将多个 Redis 命令包装成一个原子性的操作，通过 `EVAL` 命令执行脚本。由于 Lua 脚本在 Redis 服务器端执行，它能确保多个操作的原子性，并减少客户端和服务器之间的网络往返。

## 基本操作

- **EVAL**：执行 Lua 脚本

```bash
EVAL script numkeys key [key ...] arg [arg ...]
````

* `script`：Lua 脚本内容，必须是一个有效的 Lua 脚本。

* `numkeys`：键的数量，指定后面紧跟的键数。

* `key`：要操作的 Redis 键。

* `arg`：脚本的参数，可以通过 `ARGV` 在脚本中访问。

* **EVALSHA**：通过脚本的 SHA1 值执行 Lua 脚本，避免每次都上传脚本，提高性能。

```bash
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
```

## Lua 脚本示例

1. **简单的值加法操作**

```bash
EVAL "return redis.call('incr', KEYS[1])" 1 mykey
```

   该脚本将 `mykey` 的值自增 1。

2. **检查并设置操作**

```bash
EVAL "if redis.call('exists', KEYS[1]) == 1 then return redis.call('get', KEYS[1]) else return nil end" 1 mykey
```

   该脚本检查 `mykey` 是否存在，如果存在则返回其值，否则返回 `nil`。

3. **事务操作**

```bash
EVAL "redis.call('set', KEYS[1], ARGV[1]) redis.call('set', KEYS[2], ARGV[2])" 2 key1 key2 value1 value2
```

   该脚本同时为 `key1` 和 `key2` 设置值。

## 优点

* **原子性**：Lua 脚本在 Redis 内部执行，所有操作是原子性的，保证不会被其他命令打断。
* **减少网络往返**：通过将多个操作打包在一个 Lua 脚本中执行，减少了客户端与 Redis 服务器之间的网络往返，提升性能。
* **灵活性**：可以使用 Lua 语言编写复杂的逻辑，如循环、条件判断等。

## 注意事项

* **性能**：Lua 脚本执行时会阻塞 Redis 服务器，尽量避免执行时间过长的脚本。
* **脚本安全**：脚本运行时可以访问 Redis 命令，因此需要谨慎编写，避免执行不安全的操作。
* **错误处理**：如果 Lua 脚本中出现错误，整个脚本会被回滚，Redis 会返回错误信息。

## 应用场景

Lua 脚本特别适用于需要原子性操作的复杂场景，如：

* 多步操作的事务处理（例如用户余额扣款、订单处理等）。
* 减少客户端与 Redis 之间的通信次数，提高性能。
* 复杂的数据结构操作，确保在 Redis 内部完成数据处理，避免多次访问。
