面试题答案
一键面试WATCH命令的作用
WATCH命令用于在事务开始之前监控一个或多个键。当使用MULTI开启一个事务后,若被WATCH监控的键在事务执行EXEC之前被其他客户端修改,那么当前事务的EXEC命令将执行失败,返回nil,从而避免脏数据的产生,保证数据的一致性。
业务场景举例
- 库存管理场景
假设商品库存数量存储在Redis的
product:stock:{product_id}
键中。当用户下单购买商品时,我们需要先检查库存是否足够,然后减少库存。
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
product_id = 123
with r.pipeline() as pipe:
while True:
try:
# 监控库存键
pipe.watch(f'product:stock:{product_id}')
stock = pipe.get(f'product:stock:{product_id}')
if int(stock) < 1:
pipe.unwatch()
print("库存不足")
break
# 开启事务
pipe.multi()
pipe.decr(f'product:stock:{product_id}')
# 执行事务
pipe.execute()
print("下单成功,库存已减少")
break
except redis.WatchError:
# 事务执行失败,重试
continue
- 订单处理场景
例如,在创建订单时,需要保证订单编号的唯一性。假设订单编号存储在
order:next_id
键中,每次创建订单时获取并递增该编号。
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
with r.pipeline() as pipe:
while True:
try:
# 监控订单编号键
pipe.watch('order:next_id')
next_id = pipe.get('order:next_id')
if next_id is None:
next_id = 1
else:
next_id = int(next_id)
# 开启事务
pipe.multi()
pipe.set('order:next_id', next_id + 1)
# 这里可以添加创建订单的其他操作,如记录订单详情等
# 执行事务
pipe.execute()
print(f"创建订单成功,订单编号: {next_id}")
break
except redis.WatchError:
# 事务执行失败,重试
continue
在上述两个场景中,WATCH命令确保在关键数据(库存数量、订单编号)被读取后到事务执行完成期间,数据没有被其他客户端修改,从而保证了数据的一致性。