基于Lua+Redis实现库存的秒杀扣减

基于Lua+Redis实现库存的秒杀扣减

在库存扣减中,我们一般使用lua脚本来保证原子性

以下是库存和库存流水记录的lua脚本:

KEYS[1] = 库存的 key
KEYS[2] = 流水的 key
ARGV[1] = 本次要扣减的库存数
AGRV[2] = 本次扣减的唯一编号

String luaScript = """
    -- 检查操作是否已经执行过,通过检查哈希表(KEYS[2])中是否存在标识(ARGV[2])
    if redis.call('hexists', KEYS[2], ARGV[2]) == 1 then
        -- 如果存在,返回错误信息'OPERATION_ALREADY_EXECUTED'
        return redis.error_reply('OPERATION_ALREADY_EXECUTED')
    end
    -- 获取当前库存值
    local current = redis.call('get', KEYS[1])
    -- 如果库存键不存在,返回错误信息'KEY_NOT_FOUND'
    if current == false then
        return redis.error_reply('KEY_NOT_FOUND')
    end
    -- 如果当前值不是数字,返回错误信息'current value is not a number'
    if tonumber(current) == nil then
        return redis.error_reply('current value is not a number')
    end
    -- 如果当前库存小于请求的扣减数量,返回错误信息'INVENTORY_NOT_ENOUGH'
    if tonumber(current) < tonumber(ARGV[1]) then
        return redis.error_reply('INVENTORY_NOT_ENOUGH')
    end

    -- 计算新的库存值
    local new = tonumber(current) - tonumber(ARGV[1])
    -- 设置新的库存值
    redis.call('set', KEYS[1], tostring(new))

    -- 获取Redis服务器的当前时间(秒和微秒)
    local time = redis.call("time")
    -- 转换为毫秒级时间戳
    local currentTimeMillis = (time[1] * 1000) + math.floor(time[2] / 1000)
    -- 使用哈希结构存储操作日志
    redis.call('hset', KEYS[2], ARGV[2], cjson.encode({
        action = "decrease",  -- 操作类型:增加
        from = current,       -- 操作前的库存值
        to = new,             -- 操作后的库存值
        change = ARGV[1],     -- 变化量
        by = ARGV[2],         -- 操作标识
        timestamp = currentTimeMillis  -- 操作时间戳
    }))
    -- 返回新的库存值
    return new
""";

JAVA调用



    /**
     * Executes Lua script
     * 
     * @param <R> - type of result  
     * @param mode - execution mode    READ OR WRITE
     * @param luaScript - lua script    lua脚本
     * @param returnType - return type   返回类型
     * @param keys - keys available through KEYS param in script  key集合
     * @param values - values available through VALUES param in script  values参数
     * @return result object
     */
    <R> R eval(Mode mode, String luaScript, ReturnType returnType, List<Object> keys, Object... values);

    @Autowired
    private RedissonClient redissonClient;

Integer result = ((Long) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,
                    luaScript,
                    RScript.ReturnType.INTEGER,
                    Arrays.asList(KEYS[1], KEYS[2]),//KEYS[1], KEYS[2]看具体业务字段
                    ARGV[1],ARGV[2])).intValue();//ARGV[1],ARGV[2]看具体业务字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值