# 事务

## MULTI

使用 `MULTI` + `EXEC` 命令可以将一批命令一起执行。如：

``` bash
> MULTI         // 开启事务
> SET foo "foo" 
QUEUED
> INCR foo      // 提一个错误命令：对字符串自增
QUEUED
> EXEC          // 提交事务

1) OK
2) (error) ERR value is not an integer or out of range
```

但坑的是，执行期间如果有命令报错了，是不会回滚的。比如上面给字符串自增，提交后会报错，但之前的 `foo` 命令会正常执行。

所以 `MULTI` 其实不算事务，从名字上看也是，不过是批量执行。

## WATCH

使用 `WACTH` 命令可以监视一个 `key`。结合 `MULTI` 使用可以达到，在 `MULTI` 期间，如果 `key` 的值发生变化，不进行提交的效果，有点类似 `CAS` 的概念

不过由于还是用了 `MULTI` 的命令，所以并不能避免上面 `MULTI` 本身的问题（报错时无法回滚。

使用例子：

```bash
> WATCH a // 监控a
> SET a 0 // 修改a
> MULTI
> SET a 1 // 在 MULTI 里修改a。由于监控后a已经被修改了，因此这里会修改失败
> EXEC
(nil)     // 修改失败
```

## LUA

`redis` 还提供了`eval` / `evalsha` 命令来执行 `Lua` 脚本。 首先要将 `Lua` 脚本加载到 `redis` 服务端， 得到该脚本的 `SHA1` 校验和，`evalsha` 命令使用 `SHA1` 作为参数可以直接执行对应 `Lua` 脚本， 避免每次发送 `Lua` 脚本的开销。 这样客户端就不需要每次执行脚本内容， 而脚本也会常驻在服务端， 脚本功能得到了复用。

`Lua` 脚本功能为 `redis` 开发和运维人员带来如下三个好处：

1. `Lua` 脚本在 `redis` 中是**原子执行**的， 执行过程中间不会插入其他命令。
2. `Lua` 脚本可以帮助开发和运维人员创造出自己定制的命令， 并可以将这些命令常驻在 `redis` 内存中， 实现复用的效果。
3. `Lua` 脚本可以将多条命令一次性打包， 有效地减少网络开销。
