Lua脚本解决误删原子性问题
早睡蛋
# 使用Lua操作Redis
get命令
127.0.0.1:6379> EVAL "return redis.call('get','stock')" 0
"5000"
1
2
2
set命令
127.0.0.1:6379> EVAL "return redis.call('set','name','jack')" 0
OK
127.0.0.1:6379> get name
"jack"
1
2
3
4
2
3
4
改为动态参数:
127.0.0.1:6379> EVAL "return redis.call('set',KEYS[1],ARGV[1])" 1 name berry
OK
127.0.0.1:6379> get name
"berry"
1
2
3
4
2
3
4
# 设计Lua脚本
if redis.call('get',KEYS[1]) == ARGV[1]
then
return redis.call('del',KEYS[1])
else
return 0
end
key: lock
arg: uuid
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
将脚本整理成一行然后测试运行:
127.0.0.1:6379> set lock 123213123-341123-123123-12321312
OK
127.0.0.1:6379> EVAL "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock 123213123-341123-123123-12321312
(integer) 1
1
2
3
4
2
3
4
# 代码实现Lua脚本
将Lua脚本字符串复制到代码中:
String script = "if redis.call('get',KEYS[1]) == ARGV[1] " +
"then " +
"return redis.call('del',KEYS[1]) " +
"else " +
"return 0 " +
"end";
1
2
3
4
5
6
2
3
4
5
6
使用redisTemplate.execute()
方法,其中execute()内要传三个参数:
<T> T execute(RedisScript<T> script, List<K> keys, Object... args);
1
其中RedisScript源码如下:
我们实例化一个DefaultRedisScript对象即可
redisTemplate.execute(new DefaultRedisScript<>(script), Arrays.asList("lock"), uuid);
1
这里可能会出现不支持的异常,原因是new DefaultRedisScript<>(script)
中确实返回值,我们设置一下即可
redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList("lock"), uuid);
1