1. 对比Lua脚本方案与Redis自身事务
对比表格
对比维度 | Redis事务(MULTI/EXEC) | Lua脚本方案 |
---|---|---|
原子性 | 事务命令序列化执行,但中间可被其他命令打断,不保证原子性 | Lua脚本在Redis单线程中原子执行,不可中断 |
计算能力 | 仅支持Redis内置命令,无法复杂计算 | 支持Lua脚本,可实现复杂逻辑运算 |
性能 | 需多次网络交互,性能较低 | 通过SHA1复用脚本,减少网络传输,性能更高 |
适用场景 | 简单命令序列化执行 | 需要原子性且涉及复杂计算的场景 |
2. 两种运行Lua脚本的方法示例
方法1:直接发送Lua脚本(不缓存)
lua
-- Lua脚本:将key1的值加1,并返回新值
local value = tonumber(redis.call('GET', KEYS[1]))
redis.call('SET', KEYS[1], value + 1)
return value + 1
Java代码:
java
// 直接执行Lua脚本,每次传递脚本内容
RedisScript<Long> script = new DefaultRedisScript<>(
"local v=tonumber(redis.call('GET', KEYS[1])); " +
"redis.call('SET', KEYS[1], v+1); return v+1", Long.class);
Long result = redisTemplate.execute(
script, Arrays.asList("key1"), new Object[]{});
方法2:先缓存SHA1后调用
lua
-- 先执行以下脚本缓存到Redis
// 第一次执行时缓存脚本
String script = "...(同上)...";
String sha1 = redisTemplate.execute(new DefaultRedisScript<>(script, Object.class)).getSha(); // 获取SHA1
// 后续调用时仅传SHA1和参数
redisTemplate.execute(
new DefaultRedisScript<Long>(sha1, Long.class),
Arrays.asList("key1"), new Object[]{});
3. RedisScript接口及子类详解
RedisScript接口方法说明
方法名 | 作用描述 |
---|---|
getSha() |
返回脚本的SHA1哈希值(若已缓存) |
getArgsCount() |
返回脚本需要的参数数量 |
getNumberParams() |
是否需要参数(已废弃,建议用getArgsCount() ) |
getBody() |
返回脚本的原始内容(若未缓存) |
DefaultRedisScript类
-
构造方法:
javanew DefaultRedisScript<>(scriptContent, returnType); // 传入脚本内容 new DefaultRedisScript<>(sha1, returnType); // 传入SHA1
-
关键方法:
java// 设置脚本内容 script.setScriptText("lua script content"); // 设置SHA1(需确保脚本已缓存) script.setSha("computed_sha1"); // 设置参数数量 script.setArgsCount(2);
4. RedisTemplate的execute()方法对比
方法1:默认序列化器
java
// 使用默认序列化器(如StringRedisSerializer)
public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) { ... }
// 示例:执行计数器脚本
RedisScript<Long> script = new DefaultRedisScript<>(
"return tonumber(redis.call('INCR', KEYS[1]))", Long.class);
Long result = redisTemplate.execute(
script, Arrays.asList("counter_key"), new Object[]{});
方法2:自定义序列化器
java
// 自定义参数和结果的序列化方式
public <T> T execute(RedisScript<T> script,
RedisSerializer<?> argsSerializer,
RedisSerializer<T> resultSerializer,
List<K> keys, Object... args) { ... }
// 示例:处理JSON参数和结果
RedisScript<MyObject> script = ...;
MyObject result = redisTemplate.execute(
script,
Jackson2JsonRedisSerializer.class, // 参数序列化器
new Jackson2JsonRedisSerializer<>(MyObject.class), // 结果序列化器
Arrays.asList("key"),
new MyParamObject() // 自定义参数对象
);
对比表格
方法版本 | 参数序列化器 | 结果序列化器 | 适用场景 |
---|---|---|---|
默认方法 | 使用RedisTemplate默认配置 | 使用RedisTemplate默认配置 | 简单类型(如String、Long) |
自定义方法 | 可指定任意RedisSerializer | 可指定任意RedisSerializer | 复杂对象(如JSON、POJO) |