面试题答案
一键面试Lua脚本
-- 获取参数
local productId = ARGV[1]
local quantity = tonumber(ARGV[2])
local currentTime = tonumber(ARGV[3])
-- 检查库存
local stockKey = "product_stock"
local stock = redis.call('HGET', stockKey, productId)
if stock == false or tonumber(stock) < quantity then
return 0 -- 库存不足,返回0
end
-- 减少库存
redis.call('HINCRBY', stockKey, productId, -quantity)
-- 记录销售记录
local salesKey = "product_sales"
redis.call('ZADD', salesKey, currentTime, productId)
return 1 -- 操作成功,返回1
原子性保证
- Redis特性:Redis使用单线程模型处理命令,Lua脚本在Redis中执行时,整个脚本是原子性的。也就是说,在脚本执行期间,不会有其他命令插入执行,保证了脚本内多个操作的原子性。
- Lua脚本原子性:通过将库存检查、库存减少和销售记录添加这一系列操作封装在一个Lua脚本中,利用Redis对Lua脚本执行的原子性支持,确保了整个复杂事务操作要么全部成功,要么全部失败。
并发问题处理
- 库存检查与减少的一致性:由于Lua脚本的原子性,在库存检查后,其他客户端无法在本脚本执行库存减少操作之前修改库存,从而避免了超卖问题。即使多个客户端同时执行该脚本,由于脚本原子执行,库存检查和减少操作是连贯的,不会出现并发修改导致的错误。
- 有序集合插入:有序集合的插入操作同样在Lua脚本的原子执行范围内,不会出现并发插入导致的数据不一致。多个客户端并发执行脚本时,每个脚本的插入操作都按顺序原子执行,保证了销售记录按时间顺序正确记录。
在实际应用中,可以通过Redis客户端调用这个Lua脚本,并传入商品ID、购买数量和当前时间等参数,从而实现这个复杂的事务操作,并有效处理并发问题。