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