当前位置: 首页 > 工具软件 > toNumber > 使用案例 >

Redis Lua脚本应用和tonumber()的使用

益泰平
2023-12-01

官方文档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

 类似资料: