Redis提供了许多命令, 但单个命令都是原子性的. 有时候我们希望能够组合多个Redis命令一起执行, 并让这个组合也能够原子性的执行. 于是引入的了lua脚本.
- lua脚本是一段字符串. 也可以保存为单独XXX.lua文件.
编写lua
| 12
 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脚本
| 12
 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);
 }
 
 | 
执行脚本
| 12
 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 ? "库存不足" : "不能重复下单");
 }
 
 |