[关闭]
@zongwu 2017-07-18T06:31:07.000000Z 字数 1316 阅读 341

Redis 事务

api 说明 api 说明 api 说明
DISCARD 刷新一个事务中所有在排队等待的指令,并且将连接状态恢复到正常。 EXEC 执行事务中所有在排队等待的指令并将链接状态恢复到正常 MULTI 标记一个事务块的开始。
UNWATCH 刷新一个事务中已被监视的所有key。 WATCH 标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)。

MULTI & EXEC

当 redis 收到客户端发出的 MULTI 命令时,后续收到的命令不会立即执行。而是会先放到一个队列中,直到接收到 EXEC 命令。 redis 会顺序的执行队列中的所有命令,并将所有命令的运行结果打包到一起返回客户端。另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。

以下是一个事务的例子:

  1. 127.0.0.1:6379> MULTI
  2. OK
  3. 127.0.0.1:6379> INCR A
  4. QUEUED
  5. 127.0.0.1:6379> INCR B
  6. QUEUED
  7. 127.0.0.1:6379> EXEC
  8. 1) (integer) 1
  9. 2) (integer) 1

EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。
当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。

使用事务时会遇到以下2种错误:
* 执行 EXEC 之前,入队命令出错(语法错误 或 其它更严重错误)。通常服务端会记录错误,并终止事务。
* 执行 EXEC 之后,如处理了错误类型的键。最重要的是记住这样一条, 即使事务中有某条/某些命令执行失败了, 事务队列中的其他命令仍然会继续执行 —— Redis 不会停止执行事务中的命令。

redis 不支持回滚,它认为 这是编程错误应该在开发阶段被解决。正因为不用支持事务,所以能保持 redis 的简单性。

DISCARD

DISCARD命令用于清空事务的命令队列并退出事务上下文。

  1. 127.0.0.1:6379> MULTI
  2. OK
  3. 127.0.0.1:6379> INCR C
  4. QUEUED
  5. 127.0.0.1:6379> INCR C
  6. QUEUED
  7. 127.0.0.1:6379> INCR C
  8. QUEUED
  9. 127.0.0.1:6379> DISCARD
  10. OK
  11. 127.0.0.1:6379> GET C
  12. (nil)

WATCH

考虑这样的应用场景,同时两个事务要对 a 操作。起初进入事务上下文时 a 的初值均为 nil。但是由于事务的执行先后顺序(红色数字表示顺序),导致第二个事务的初值是99而非nil

image_1bla4kdkp8d66kq14ret4l1vkk9.png-28.4kB

为了避免脏读,所以 redis 使用 WATCH 来添加乐观锁。执行结果就比较直观了(见下图),监察到观察的对象有变更过则会执行失败。所以也比较好理解 EXECDISCARDUNWATCH 都会清除连接中的 WATCH

image_1bla51tcaa6cr0q16j44p31tc3m.png-19kB

所以当考虑到两个事务的键有碰撞时,需要有重试机制确保事务不会被丢弃。当然碰撞的情况一般会很少,所以一般也无需重试。

EVAL

从定义上来说, Redis 中的 EVAL 本身就是一种事务, 所以任何在事务里可以完成的事, 在 EVAL 里面也能完成。 并且一般来说, 使用 EVAL 要来得更简单,并且速度更快。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注