MST
星途 面试题库

面试题:Redis中WATCH命令的基本使用场景是什么

请阐述在哪些常见业务场景下会使用到Redis的WATCH命令,并且说明使用该命令如何保障数据的一致性。同时,给出一个简单的代码示例(语言不限)展示WATCH命令与MULTI、EXEC组合使用的基本流程。
41.3万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

常见业务场景

  1. 银行转账:在进行资金从一个账户转移到另一个账户的操作时,需要确保两个账户余额的修改是原子性的,并且在操作过程中两个账户的余额不会被其他进程修改。
  2. 库存管理:当商品库存数量减少时,需要保证库存数量在读取和更新之间不会被其他业务逻辑修改,以防止超卖情况。
  3. 分布式系统中的资源竞争:例如多个节点同时竞争有限的资源,需要保证资源分配过程中的数据一致性。

保障数据一致性原理

Redis 的 WATCH 命令用于监控一个或多个键。在执行 WATCH 后,直到 EXEC 执行前,如果被监控的键被其他客户端修改,那么当前客户端的事务将被打断,EXEC 返回 nil,事务不会执行。这样可以确保在 WATCH 开始到 EXEC 之间,被监控的数据没有发生变化,从而保障了数据的一致性。

代码示例(Python)

import redis

# 连接到 Redis 服务器
r = redis.Redis(host='localhost', port=6379, db=0)

# 使用 WATCH、MULTI、EXEC 组合
def transfer(sender, receiver, amount):
    pipe = r.pipeline()
    while True:
        try:
            # 监控发送者和接收者账户余额
            pipe.watch(sender, receiver)
            sender_balance = pipe.get(sender)
            receiver_balance = pipe.get(receiver)
            if sender_balance is None or receiver_balance is None:
                raise ValueError("账户不存在")
            sender_balance = int(sender_balance)
            receiver_balance = int(receiver_balance)
            if sender_balance < amount:
                raise ValueError("余额不足")
            # 开始事务
            pipe.multi()
            pipe.decrby(sender, amount)
            pipe.incrby(receiver, amount)
            # 执行事务
            pipe.execute()
            return True
        except redis.WatchError:
            # 事务执行失败,重试
            continue
        finally:
            pipe.unwatch()

# 示例调用
if transfer('account1', 'account2', 100):
    print("转账成功")
else:
    print("转账失败")

在上述代码中,transfer 函数实现了从 sender 账户向 receiver 账户转账 amount 金额的功能。通过 WATCH 监控两个账户余额,确保在读取余额和修改余额之间,余额不会被其他客户端修改。如果在 WATCHEXEC 之间余额被修改,EXEC 会失败,代码会捕获 WatchError 并重新尝试整个操作。