/*
* -3:库存未初始化
* -2:库存不足
* -1:不限库存
* 大于等于0: 剩余库存(扣减之后剩余的库存), 直接返回-1
*/
Redis::invoke(function (ESRedis $redis) {
$userId = (10000 * microtime(true)) . rand(100, 9999);
$num = rand(1, 3);
$goodsKey = "skill:goods:1";
$orderKey = "skill:order:1";
$script = <<<SCRIPT
if redis.call('exists',KEYS[1]) ~= 1 then
return -3
end
local stock = tonumber(redis.call('get',KEYS[1]))
local num = tonumber(ARGV[1])
if stock == -1 then
return -1
end
if stock >= num then
redis.call('lpush',KEYS[2],ARGV[2])
return redis.call('incrby',KEYS[1],0-num)
end
return -2
SCRIPT;
return $redis->rawCommand([
'EVAL',
$script,
2,
$goodsKey,
$orderKey,
$num,
$userId . ',' . $num
]);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$key = 'buy';
$limitNum = 100;
$ttl = 1;
Redis::invoke(function (ESRedis $redis) use ($key, $limitNum, $ttl) {
$lua = <<<SCRIPT
redis.call('zAdd',KEYS[1],tonumber(ARGV[2]),ARGV[3])
redis.call('zRemRangeByScore',KEYS[1],0,tonumber(ARGV[2])-tonumber(ARGV[1]))
redis.call('expire',KEYS[1],tonumber(ARGV[1]))
local num = redis.call('zCount',KEYS[1],0,tonumber(ARGV[2]))
if num > tonumber(ARGV[4]) then
return 1
else
return 0
end
SCRIPT;
$score = time();
$nonce = uniqid() . (10000 * microtime(true));
return $redis->rawCommand([
'EVAL',
$lua,
1,
$key,
$ttl,
$score,
$nonce,
$limitNum,
]);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29