文章目录加载中

Redis watch 命令学习

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

如何取消监听?

使用UNWATCH命令,取消所有监听。

# 演示

例 1:

127.0.0.1:6379> get key
"3"
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR key
QUEUED
127.0.0.1:6379(TX)> EXEC
1) (integer) 4
127.0.0.1:6379> get key
"4"
  1. 监听 key
  2. 开始事务
  3. 提交事务:由于事务开始前,没有修改 key 的值,因此事务执行成功,key 的值更新为 4

例 2:

127.0.0.1:6379> get key
"4"
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> set key 5
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set key_2 100
QUEUED
127.0.0.1:6379(TX)> set key 100
QUEUED
127.0.0.1:6379(TX)> set key_2 1000
QUEUED
127.0.0.1:6379(TX)> EXEC
(nil)
127.0.0.1:6379> get key
"5"
127.0.0.1:6379> get key_2
"2"
  1. key 和 key_2 分别为 4 和 2
  2. 监听 key 的值
  3. 事务开始前修改 key 值
  4. 开始事务,在事务中尝试修改 key 和 key_2 的值
  5. 提交事务:由于事务开始前,修改了 key 的值,因此事务整体失败。获取的 key 和 key_2 的值是事务之前的。

# 用途

可以用来被用来将几个操作封装成一个原子操作,避免出现「竞态」条件。

伪代码如下:

def hsetxx($key, $field, $value)
  WATCH $key
  $isFieldExists = HEXISTS $key, $field
  if $isFieldExists is 1
    MULTI
    HSET $key, $field, $value
    EXEC
  else
    UNWATCH
  return $isFieldExists

为什么这里会这样用呢?

在上面代码中,事务启动的条件,是$isFieldExists为 true。如果进行监听,直接读取$isFieldExists 的值,然后开启事务。那么在读取之后,如果其它客户端修改此值,正确情况是事务不执行,但是由于这里读到的是旧值,因此依然会执行(错误情况)。

利用 watch,相当于拿到了值的「快照」,提交事务的时候,如果真实值和快照的值不同,那么就不会执行

本文来自心谭博客:xin-tan.com,经常更新web和算法的文章笔记,前往github查看目录归纳:github.com/dongyuanxin/blog