RedisTemplate 是 Spring Boot 调用 Lua 脚本最直接稳定的入口,需通过 execute() 传 RedisScript 和参数,脚本中 key 必须用 KEYS[]、参数用 ARGV[],且所有 key 需同 slot;加载本地 .lua 文件应使用 Resource + InputStream 方式并设置 SHA1;集群下跨 slot 操作会报 CROSSSLOT 错误,须用 {xxx} 哈希标签或拆分脚本;避免使用 StringRedisTemplate.execute() 防 ClassCastException。

RedisTemplate 是 Spring Boot 中调用 Lua 脚本最直接、最稳定的入口,不需要额外封装工具类或自定义连接池。
怎么用 RedisTemplate.execute() 执行 Lua 脚本
核心是调用 execute() 方法,传入 RedisScript 对象和参数。别直接拼字符串或手写 eval 命令——Spring 已经封装好安全边界。
-
RedisScript必须声明返回类型(如Long.class、String.class或List.class),否则执行时抛IllegalArgumentException - 脚本中用
KEYS[1]引用第一个 key,ARGV[1]引用第一个参数;Spring 会自动把keys列表和args数组映射过去 - 不要在脚本里写
redis.call("get", "hardcoded-key")——所有 key 必须通过KEYS传入,否则集群模式下报错CROSSSLOT Keys in request don't hash to the same slot - 示例:限流脚本
rate_limit.lua内容为local count = redis.call("incr", KEYS[1]); if count == 1 then redis.call("expire", KEYS[1], ARGV[1]) end; return count,Java 调用时传Arrays.asList("rate:uid:123")作 keys,Arrays.asList("60")作 args
DefaultRedisScript 怎么加载本地 .lua 文件
Spring 不自动扫描 src/main/resources/lua/ 目录,必须手动读取并构造 DefaultRedisScript 实例。
- 脚本文件路径用
classpath:lua/rate_limit.lua,不是相对路径或绝对路径 - 必须显式调用
script.setSha1(...)或让 Spring 计算 SHA1(首次执行时上传,后续用 SHA1 缓存脚本),否则每次请求都发完整脚本文本,浪费带宽 - 如果脚本内容不变但修改了文件换行符或空格,SHA1 会变,Redis 会重复加载——建议用
git diff确认脚本二进制一致性 - 不推荐用
ResourceUtils.getFile("classpath:..."),它在 jar 包里会抛FileNotFoundException;应始终用Resource+InputStream方式读取
集群环境下 Lua 脚本的 key 分布限制
Redis Cluster 要求一个脚本内所有 KEYS 必须落在同一个哈希槽(slot),否则直接拒绝执行。
- 单 key 操作天然满足条件;多 key 场景必须用
{xxx}语法保证哈希标签一致,例如user:{123}:profile和user:{123}:settings - 不能写
redis.call("mget", KEYS[1], KEYS[2])且两个 key 不带相同哈希标签——运行时报CROSSSLOT - 若业务必须跨 slot 操作(如用户信息+订单列表),拆成多个脚本调用,或改用客户端逻辑聚合结果
- Lettuce 客户端默认开启
cluster模式检测,遇到违规脚本会立即抛RedisCommandExecutionException,而不是静默失败
为什么不用 StringRedisTemplate.execute()?
看起来更“字符串友好”,但实际埋坑:它内部仍用 RedisTemplate,只是对序列化器做了简化封装,而 Lua 脚本返回值类型由脚本本身决定,与 key/value 的序列化无关。
- 若脚本返回数字(如计数器结果),用
StringRedisTemplate会导致ClassCastException:它试图把Long强转成String - 统一用
RedisTemplate+ 显式泛型(RedisTemplate<string string></string>)即可兼顾类型安全和字符串操作需求 - 除非你确定脚本只返回字符串且永不变更,否则不要贪图省事切换模板
CROSSSLOT 边界测试,比本地单机验证重要得多。


















