在 Redis 中,WATCH
命令是事务机制的一部分,用于实现乐观锁(optimistic locking)。它允许客户端监控一个或多个键,然后在执行 EXEC
命令提交事务之前检查这些键是否被其他客户端修改。如果这些键被修改了,那么当前客户端的事务将会失败。
工作原理
-
开始监控:
- 客户端使用
WATCH
命令来指定要监控的一个或多个键。 - 例如:
WATCH key1 key2
- 客户端使用
-
多命令队列:
- 在调用
WATCH
之后,客户端可以继续发送多个命令到服务器,但这些命令会被放入一个事务队列中,并不会立即执行。
- 在调用
-
执行事务:
- 当客户端准备好执行事务时,它会发送
MULTI
命令来开启一个事务块。 - 接着发送需要执行的命令,这些命令也会被加入到事务队列中。
- 最后,客户端发送
EXEC
命令来尝试执行事务中的所有命令。
- 当客户端准备好执行事务时,它会发送
-
检查和执行:
- 在执行
EXEC
命令时,Redis 会检查自上次WATCH
命令以来,被监控的键是否被其他客户端修改过。 - 如果没有其他客户端修改这些键,那么事务中的所有命令将按顺序执行,并且结果返回给客户端。
- 如果有其他客户端修改了这些键,那么整个事务将会被取消,
EXEC
返回nil
或者空数组,表示事务执行失败。
- 在执行
-
取消监控:
- 如果事务成功执行或者客户端决定不执行事务(通过发送
DISCARD
命令),则对这些键的监控自动解除。 - 客户端也可以显式地使用
UNWATCH
命令来取消对所有键的监控。
- 如果事务成功执行或者客户端决定不执行事务(通过发送
示例
假设有一个名为 balance
的键,其值为用户的账户余额。两个客户端同时试图更新这个余额:
-
客户端 A:
WATCH balance GET balance MULTI SET balance 100 EXEC
-
客户端 B:
WATCH balance GET balance MULTI SET balance 200 EXEC
假设初始状态下 balance
的值为 50。
- 如果客户端 A 先执行
EXEC
,那么balance
将被设置为 100。 - 当客户端 B 执行
EXEC
时,Redis 会发现balance
自从客户端 B 发出WATCH
后已经被修改(由客户端 A 修改),因此客户端 B 的事务会失败,EXEC
返回nil
。
使用场景
WATCH
通常用于那些需要保证数据一致性的场景,特别是在并发环境下。例如,在购物车结算、库存管理等应用场景中,可以确保在处理订单时商品数量不会出现错误。
注意事项
WATCH
只能在一个连接上工作,如果你在一个连接上设置了WATCH
,然后在另一个连接上修改了被监控的键,WATCH
仍然能够检测到这种变化。WATCH
和事务机制一起提供了一种简单的乐观锁实现方式,但它并不适用于所有的并发控制需求。对于更复杂的事务需求,可能需要考虑其他数据库系统或者更高级的分布式锁机制。
通过 WATCH
,Redis 提供了一个简单而强大的工具来处理并发环境下的数据一致性问题。