RedisLua脚本应用和tonumber()的使用

原创
小哥 2年前 (2023-05-17) 阅读数 41 #大杂烩

官方文档 http://redisdoc.com/script/eval.html

1、释放分布式锁:

if redis.call(get,KEYS[1]) == ARGV[1] then
    return redis.call(del,KEYS[1])
else
    return 0
end

PHP中应用:

/**
 * 释放锁
 * @return bool
 */
public function release()
{
    return (bool)$this->redis->eval(释放分布式锁lua, 1, $this->key, $this->value);
}

2、抢购中减库存:需提前将总库存存入redis

if tonumber(ARGV[1]) <= tonumber(redis.call(get, KEYS[1])) then
    return redis.call(decrby, KEYS[1], ARGV[1]) + 1
else
    return 0
end

tonumber()属于redis内部函数,作用是将参数转为数字(进行大小比较时必须转),否则结果错误。
这里+1目的是确保消费最后一个库存时结果返回的bool值为true

PHP中应用:

/**
 * 减库存
 * @param $key
 * @param $decrement 减量
 * @return bool
 */
public function stockDeCrBy($key, $decrement)
{
    return (bool)$this->redis->eval(抢购中减库存lua, 1, $key, $decrement);
}

LUA返回多个值:

local stock = tonumber(redis.call(get, KEYS[1]));
if tonumber(ARGV[1]) <= stock then
    local stock = tonumber(redis.call(decrby, KEYS[1], ARGV[1]));
    return {stock + 1,stock}
else
    return {0,stock}
end

/**
 * 减库存
 * @param $key
 * @param $decrement 减量
 * @return bool
 */
public function stockDeCrBy($key, $decrement, &$stock)
{
    list($res, $stock) = $this->redis->eval(抢购中减库存lua, 1, $key, $decrement);
    return (bool)$res;
}

if (!$model->stockDeCrBy(goods_id_123456789, 10, $stock)) {
    //此处变量$stock无需定义,因为其在stockDeCrBy是传址
    throw new Exception(剩余商品.$stock.件,不够售卖,请增加库存);
}

判断key是否存在使用 redis.call(exists,KEYS[1]) == 1

3、抢购中加销量:不需要提前存总库存入redis

if 1 == redis.call(exists,KEYS[1]) then 
    if tonumber(ARGV[2]) < (tonumber(ARGV[1]) + tonumber(redis.call(get,KEYS[1]))) then 
        return 0
    else
        return redis.call(incrby,KEYS[1],ARGV[1])
    end
else
    return redis.call(incrby,KEYS[1],ARGV[1])
end

或者定义local局部变量:

local key = KEYS[1];
local increment = ARGV[1];
local stock = ARGV[2];
if 1 == redis.call(exists,key) then 
    if tonumber(stock) < (tonumber(increment) + tonumber(redis.call(get,key))) then 
        return 0
    else
        return redis.call(incrby,key,increment)
    end
else
    return redis.call(incrby,key,increment)
end

PHP中应用:

/**
 * 增销量
 * @param $key
 * @param $increment 增量
 * @param $stock 总库存
 * @return bool
 */
public function saleInCrBy($key, $increment, $stock)
{
    return (bool)$this->redis->eval(抢购中加销量lua, 1, $key, $increment, $stock);
}

比较复杂的LUA脚本最好是缓存入redis内部,使用evalsha命令对脚本进行复用,免去了无谓的带宽消耗。 http://redisdoc.com/script/evalsha.html

在PHP中的应用: https://blog.csdn.net/Gan_1314/article/details/125296018

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除