Spring Boot 集成Redis 的Lua脚本详解

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类
  • 构造方法

    java 复制代码
    new 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)
相关推荐
呼拉拉呼拉5 分钟前
Redis高可用架构
数据库·redis·架构·高可用架构
编程乐学(Arfan开发工程师)43 分钟前
42、响应处理-【源码分析】-浏览器与PostMan内容协商完全适配
java·spring boot·后端·测试工具·lua·postman
用户79117724235831 小时前
黑马点评【基于redis实现共享session登录】
java·redis
javadaydayup1 小时前
明明说好的国际化,可你却还是返回了中文
spring boot·后端·spring
观无2 小时前
redis分布式锁
数据库·redis·分布式
eternal__day2 小时前
Spring Cloud 多机部署与负载均衡实战详解
java·spring boot·后端·spring cloud·负载均衡
颜淡慕潇2 小时前
Redis 实现分布式锁:深入剖析与最佳实践(含Java实现)
java·redis·分布式
程序员秘密基地2 小时前
基于vscode,idea,java,html,css,vue,echart,maven,springboot,mysql数据库,在线考试系统
java·vue.js·spring boot·spring·web app
CV点灯大师2 小时前
C++算法训练营 Day10 栈与队列(1)
c++·redis·算法
风象南3 小时前
SpringBoot的5种日志输出规范策略
java·spring boot·后端