Redis提供了许多命令, 但单个命令都是原子性的. 有时候我们希望能够组合多个Redis命令一起执行, 并让这个组合也能够原子性的执行. 于是引入的了lua脚本.
- lua脚本是一段字符串. 也可以保存为单独XXX.lua文件.
编写lua
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
|
local voucherId = ARGV[1]
local userId = ARGV[2]
local orderId = ARGV[3]
local stockKey = 'seckill:stock:' .. voucherId
local orderKey = 'seckill:order:' .. voucherId
if(tonumber(redis.call('get', stockKey)) <= 0) then return 1 end
if(redis.call('sismember', orderKey, userId) == 1) then return 2 end
redis.call('incrby', stockKey, -1)
redis.call('sadd', orderKey, userId)
redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId) return 0
|
导入lua脚本
1 2 3 4 5 6 7
| private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
static { SECKILL_SCRIPT = new DefaultRedisScript<>(); SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua")); SECKILL_SCRIPT.setResultType(Long.class); }
|
执行脚本
1 2 3 4 5 6 7 8 9 10 11 12
| Long result = stringRedisTemplate.execute( SECKILL_SCRIPT, Collections.emptyList(), voucherId.toString(), userId.toString(), String.valueOf(orderId) ); int r = result.intValue();
if (r != 0) { return Result.fail(r == 1 ? "库存不足" : "不能重复下单"); }
|