@zongwu
2017-07-18T06:31:07.000000Z
字数 1316
阅读 341
api | 说明 | api | 说明 | api | 说明 |
---|---|---|---|---|---|
DISCARD | 刷新一个事务中所有在排队等待的指令,并且将连接状态恢复到正常。 | EXEC | 执行事务中所有在排队等待的指令并将链接状态恢复到正常 | MULTI | 标记一个事务块的开始。 |
UNWATCH | 刷新一个事务中已被监视的所有key。 | WATCH | 标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)。 |
当 redis 收到客户端发出的 MULTI 命令时,后续收到的命令不会立即执行。而是会先放到一个队列中,直到接收到 EXEC 命令。 redis 会顺序的执行队列中的所有命令,并将所有命令的运行结果打包到一起返回客户端。另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。
以下是一个事务的例子:
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR A
QUEUED
127.0.0.1:6379> INCR B
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 1
2) (integer) 1
EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。
当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。
使用事务时会遇到以下2种错误:
* 执行 EXEC 之前,入队命令出错(语法错误 或 其它更严重错误)。通常服务端会记录错误,并终止事务。
* 执行 EXEC 之后,如处理了错误类型的键。最重要的是记住这样一条, 即使事务中有某条/某些命令执行失败了, 事务队列中的其他命令仍然会继续执行 —— Redis 不会停止执行事务中的命令。
redis 不支持回滚,它认为 这是编程错误应该在开发阶段被解决。正因为不用支持事务,所以能保持 redis 的简单性。
DISCARD命令用于清空事务的命令队列并退出事务上下文。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR C
QUEUED
127.0.0.1:6379> INCR C
QUEUED
127.0.0.1:6379> INCR C
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> GET C
(nil)
考虑这样的应用场景,同时两个事务要对 a
操作。起初进入事务上下文时 a
的初值均为 nil
。但是由于事务的执行先后顺序(红色数字表示顺序),导致第二个事务的初值是99
而非nil
。
为了避免脏读,所以 redis 使用 WATCH 来添加乐观锁。执行结果就比较直观了(见下图),监察到观察的对象有变更过则会执行失败。所以也比较好理解 EXEC、DISCARD、UNWATCH 都会清除连接中的 WATCH 。
所以当考虑到两个事务的键有碰撞时,需要有重试机制确保事务不会被丢弃。当然碰撞的情况一般会很少,所以一般也无需重试。
从定义上来说, Redis 中的 EVAL 本身就是一种事务, 所以任何在事务里可以完成的事, 在 EVAL 里面也能完成。 并且一般来说, 使用 EVAL 要来得更简单,并且速度更快。