4.监控
watch 命令用于客户端并发情况下,为事务提供一个乐观锁(CAS,Check And Set),也就是可以用 watch 命令来监控一个或多个变量,如果在事务的过程中,某个监控项被修改了,那么整个事务就会终止执行。watch 基本语法如下:
watch key [key ...]
watch示例代码如下:
> watch k OK > multi OK > set k v2 QUEUED > exec (nil) > get k "v"
从以上命令可以看出,如果 exec 返回的结果是 nil 时,表示 watch 监控的对象在事务执行的过程中被修改了。从 getk 的结果也可以看出,在事务中设置的值 setk v2 并未正常执行。执行流程如下图所示:
注意:
watch 命令只能在客户端开启事务之前执行,在事务中执行 watch 命令会引发错误,但不会造成整个事务失败,如下代码所示:
> multi OK > set k v3 QUEUED > watch k (error) ERR WATCH inside MULTI is not allowed > exec 1) OK > get k "v3"
执行命令解释如下图所示:
unwatch 命令用于清除所有之前监控的所有对象(键值对)。unwatch 示例如下所示:
> set k v OK > watch k OK > multi OK > unwatch QUEUED > set k v2 QUEUED > exec 1) OK 2) OK > get k "v2"
可以看出,即使在事务的执行过程中,k 值被修改了,因为调用了 unwatch
命令,整个事务依然会顺利执行。
5.事务在程序中使用
以下是事务在 Java 中的使用,代码如下:
import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; public class TransactionExample { public static void main(String[] args) { // 创建 Redis 连接 Jedis jedis = new Jedis("xxx.xxx.xxx.xxx", 6379); // 设置 Redis 密码 jedis.auth("xxx"); // 设置键值 jedis.set("k", "v"); // 开启监视 watch jedis.watch("k"); // 开始事务 Transaction tx = jedis.multi(); // 命令入列 tx.set("k", "v2"); // 执行事务 tx.exec(); System.out.println(jedis.get("k")); jedis.close(); } }
6.小结
事务为多个命令提供一次性按顺序执行的机制,与 Redis 事务相关的命令有以下五个:
- multi:开启事务
- exec:执行事务
- discard:丢弃事务
- watch:为事务提供乐观锁实现
- unwatch:取消监控(取消事务中的乐观锁)
正常情况下 Redis 事务分为三个阶段:开启事务、命令入列、执行事务。Redis 事务并不支持运行时错误的事务回滚,但在某些入列错误,如 setkey
或者是 watch
监控项被修改时,提供整个事务回滚的功能。
7.思考题
Redis 事务中如何解决并发修改的问题?Redis 支持事务回滚吗?使用 Redis 事务时会出现哪三种错误?这三种错误对事务有何影响?只有高手才能答对的问题,你能答上来几个?