Scripting

Redis 2.6 及更高版本通过 evalevalsha 命令支持运行 Lua 脚本。Spring Data Redis 为运行脚本提供了一个高级抽象,它处理序列化并自动使用 Redis 脚本缓存。

可以通过调用`RedisTemplate`和`ReactiveRedisTemplate`的`execute`方法来运行脚本。两者都使用可配置的`ScriptExecutor`(或`ReactiveScriptExecutor`)来运行提供的脚本。默认情况下,ScriptExecutor(或`ReactiveScriptExecutor`)负责序列化提供的键和参数,以及反序列化脚本结果。这是通过模板的键和值序列化器完成的。还有一个附加的重载,它允许你传递用于脚本参数和结果的自定义序列化器。

默认的`ScriptExecutor`通过检索脚本的 SHA1 并首先尝试运行`evalsha`来优化性能,如果脚本尚不存在于 Redis 脚本缓存中,则回调`eval`。

以下示例通过使用 Lua 脚本运行常见的“check-and-set”场景。这是 Redis 脚本的理想用例,因为它要求以原子方式运行一组命令,并且一个命令的行为受到另一命令结果的影响。

@Bean
public RedisScript<Boolean> script() {

  ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("META-INF/scripts/checkandset.lua"));
  return RedisScript.of(scriptSource, Boolean.class);
}
  • Imperative

  • Reactive

public class Example {

  @Autowired
  RedisOperations<String, String> redisOperations;

  @Autowired
  RedisScript<Boolean> script;

  public boolean checkAndSet(String expectedValue, String newValue) {
    return redisOperations.execute(script, singletonList("key"), asList(expectedValue, newValue));
  }
}
public class Example {

  @Autowired
  ReactiveRedisOperations<String, String> redisOperations;

  @Autowired
  RedisScript<Boolean> script;

  public Flux<Boolean> checkAndSet(String expectedValue, String newValue) {
    return redisOperations.execute(script, singletonList("key"), asList(expectedValue, newValue));
  }
}
-- checkandset.lua
local current = redis.call('GET', KEYS[1])
if current == ARGV[1]
  then redis.call('SET', KEYS[1], ARGV[2])
  return true
end
return false

前面的代码配置了一个指向名为`checkandset.lua`文件的`RedisScript`,该文件预期返回一个布尔值。脚本`resultType`应该是`Long`、BooleanList`或反序列化的值类型之一。如果脚本返回一次性状态(具体来说是`OK),它也可以是`null`。

在应用程序上下文中配置 DefaultRedisScript 的单个实例是理想的,以避免在每次运行脚本时重新计算脚本的 SHA1。

上述的 checkAndSet 方法随后运行脚本。脚本可以在 SessionCallback 中作为事务或管道的部分来运行。有关更多信息,请参见 “Redis Transactions” 和 “Pipelining”。

Spring Data Redis 提供的脚本支持也允许您使用 Spring 任务和调度器抽象对 Redis 脚本进行计划以定期运行。有关更多详细信息,请参见 Spring Framework 文档。