spring data redis 不支持自动注入lua脚本,需手动用resourceloader读取文件内容并构建redisscript对象后调用execute()执行;keys必须非空且同slot,argv顺序不可颠倒。

Spring Data Redis 无法直接“动态注入”Lua脚本文件
Spring Data Redis 没有提供类似 @Value("classpath:lua/xxx.lua") 自动读取并注册脚本的机制。所谓“动态注入”,实际是指在运行时加载本地 Lua 文件内容、构建 RedisScript 对象,并传给 execute() 方法——它不涉及 Redis 服务端的 SCRIPT LOAD 或缓存管理,只是客户端拼装脚本内容再发送。
用 Resource 读取 .lua 文件内容必须手动做
Spring Boot 的 ResourceLoader 可以定位 classpath 下的 Lua 脚本,但你要自己读成字符串,不能跳过这步:
-
Resource必须用resource.getInputStream()或resource.getContentAsString(StandardCharsets.UTF_8)获取文本内容 - 路径写错会导致
FileNotFoundException,比如写成lua/get_or_set_default.lua却放在resources/scripts/下 - 脚本含中文或特殊符号时,务必指定 UTF-8 编码,否则
redis.call()执行时报LUA ERR Error compiling script (new way) - 推荐用
StringRedisTemplate配合DefaultRedisScript<string></string>,避免泛型擦除导致返回值类型错误
示例片段:
Resource scriptResource = resourceLoader.getResource("classpath:lua/get_or_set_default.lua");
String luaContent = StreamUtils.copyToString(scriptResource.getInputStream(), StandardCharsets.UTF_8);
DefaultRedisScript<string> script = DefaultRedisScript.<string>builder()
.scriptText(luaContent)
.resultType(String.class)
.build();</string></string>
execute() 调用时 KEY 和 ARGV 顺序不能颠倒
Redis 要求所有键名(KEYS)必须显式前置,且数量由第二个参数(numKeys)严格控制;其余全算 ARGV。Spring Data Redis 的 execute(script, keys, args...) 签名容易误导:
- keys 参数是
List<string></string>或Collection<string></string>,不是 varargs —— 它对应KEYS[1], KEYS[2]... - args 是可变参数(
Object...),对应ARGV[1], ARGV[2]... - 如果脚本里用了
redis.call("GET", KEYS[1]),但传了空keys列表,会报ERR Error running script (call to f_...): @user_script:3: user_script:3: attempt to index a nil value (field '1') - 集群模式下,所有
KEYS必须落在同一个 slot,否则抛RedisClusterException;单机模式无此限制
正确调用示例:
String result = stringRedisTemplate.execute(
script,
Collections.singletonList("my:key"), // ← keys 列表,长度=1
"default:val" // ← args,对应 ARGV[1]
);
别把 scriptLoad 和客户端脚本加载混为一谈
Redis 的 SCRIPT LOAD 是服务端行为,返回 SHA1 值供后续 EVALSHA 复用;而 Spring Data Redis 的 execute() 默认走 EVAL,每次发完整脚本文本。除非你显式调用 redisTemplate.getConnectionFactory().getConnection().scriptLoad(...),否则不会触发服务端缓存。
- 高频脚本建议提前
scriptLoad一次,之后用evalsha,减少网络传输量 - 但
scriptLoad返回的 SHA1 在集群模式下只对当前节点有效,跨节点需重复加载 - 应用重启后服务端脚本不会自动重载,得自己加初始化逻辑(比如
@PostConstruct) - 脚本内容变更后,SHA1 改变,旧的
evalsha会失败并报NOSCRIPT No matching script,此时要 fallback 到eval
真正容易被忽略的是:你写的 get_or_set_default.lua 文件本身没任何“注入”能力,它只是个文本资源;所有解析、编码、序列化、网络发送动作,都发生在你调用 execute() 的那一瞬间——没有魔法,只有你亲手组装的字符串和参数。











