开发者

SpringBoot集成Redis并调用Lua脚本的示例详解

开发者 https://www.devze.com 2025-07-17 10:33 出处:网络 作者: 超级小忍
目录前言一、项目准备二、编写 Lua 脚本文件三、加载 Lua 脚本到 Redis四、封装 Lua 脚本调用服务五、创建 REST 接口进行测试六、运行测试1. 启动 Redis 服务2. 启动 Spring Boot 应用3. 测试访问七、注意事项八、进
目录
  • 前言
  • 一、项目准备
  • 二、编写 Lua 脚本文件
  • 三、加载 Lua 脚本到 Redis
  • 四、封装 Lua 脚本调用服务
  • 五、创建 REST 接口进行测试
  • 六、运行测试
    • 1. 启动 Redis 服务
    • 2. 启动 Spring Boot 应用
    • 3. 测试访问
  • 七、注意事项
    • 八、进阶建议
      • 示例结构图
        • 总结

          前言

          Redis 是一个高性能的内存数据库,广泛用于缓存、计数器、分布式锁等场景。在某些业务中,我们需要对多个 Redis 操作进行原子性处理,以保证数据一致性,这时就可以使用 Redis 提供的 Lua 脚本功能。

          Spring Boot 通过 RedisTemplate 对 Redis 进行了良好的封装,也支持我们方便地调用 Lua 脚本。本文将带你一步步实现 Spring Boot 中如何:

          • 加载 Lua 脚本
          • 调用 Lua 脚本
          • 实现一个实际业务逻辑:获取 key,若不存在则设置默认值并返回

          一、项目准备

          创建 Spring Boot 项目

          你可以使用 Spring Initializr 创建一个新项目,选择以下依赖:

          • Spring Web
          • Spring Data Redis
          • Lettuce(Redis 客户端)

          或者手动创建 Maven 项目后添加如下依赖:

          <!-- Spring Boot Starter -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-startephpr</artifactId>
          </dependency>
          
          <!-- Web 支持 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
          </dependency>
          
          <!-- Redis 支持 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          
          <!-- Lettuce 客户端 -->
          <dependency>
              <groupId>io.lettuce.core</groupId>
              <artifactId>lettuce-core</artifactId>
              <version>6.2.4</version>
          </dependency>
          

          二、编写 Lua 脚本文件

          我们将创建一个简单的 Lua 脚本:如果 key 不存在,则设置默认值;存在则直接返回当前值。

          脚本内容:get_or_set_default.lua

          路径建议为:src/main/resources/lua/get_or_set_default.lua

          -- get_or_set_default.lua
          local key = KEYS[1]
          local defaultVal = ARGV[1]
          
          local value = redis.call('GET', key)
          if not value then
              redis.call('SET', key, defaultVal)
              value = defaultVal
          end
          return value
          

          三、加载 Lua 脚本到 Redis

          我们可以利用 Spring 的生命周期回调(如 @PostConstruct)来加载 Lua 脚本,并保存其 SHA1 校验码,后续通过 EVALSHA 来调用。

          创建脚本加载类:LuaScriptLoader.Java

          import org.springframework.data.redis.core.RedisTemplate;
          import org.springframework.data.redis.core.script.DefaultRedisScript;
          import org.springframework.stereotype.Service;
          
          import javax.anwww.devze.comnotation.PostConstruct;
          import java.io.IOException;
          import java.nio.file.Files;
          import java.nio.file.Path;
          import java.nio.file.Paths;
          import java.util.Collections;
          
          @Service
          public class LuaScriptLoader {
          
              private final RedisTemplate<String, Object> redisTemplate;
          
              // 存储脚本的 SHA1 值
              public static String GET_OR_SET_DEFAULT_SHA;
          
              public LuaScriptLoader(RedisTemplate<String, Object> redisTemplate) {
                  this.redisTemplate = redisTemplate;
              }
          
              @PostConstruct
              public void loadScripts() throws IOException {
                  Path scriptPath = Paths.get("src/main/resources/lua/get_or_set_default.lua");
                  String scriptContent = Files.readString(scriptPath);
          
                  DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
                  redisScript.setScriptText(scriptContent);
                  redisScript.setResultType(String.class);
          
                  // 执行 SCRIPT LOAD 命令加载脚本
                  GET_OR_SET_DEFAULT_SHA = redisTemplate.execute(
                          redisScript,
                          Collections.singletonList("dummyKey"),
                          "defaultValue"
                  );
          
                  System.out.println("Lua Script SHA1: " + GET_OR_SET_DEFAULT_SHA);
              }
          }
          

          注意:

          • 我们使用了一个 dummyKey 和 dummyValue 来执行一次脚本,只是为了触发脚本加载。
          • 实际调用时使用的是 EVALSHA 命令。

          四、封装 Lua 脚本调用服务

          我们创建一个服务类来封装 Lua 脚本的调用逻辑。

          创建服务类:RedisLuaService.java

          import org.springframework.data.redis.core.RedisTemplate;
          import org.springframework.stereotype.Service;
          
          import java.util.Collections;
          
          @Service
          public class RedisLuaService {
          
              private final RedisTemplate<String, Object> redisTemplate;
          
              public RedisLuaService(RedisTemplate<String, Object> redisTemplate) {
                  this.redisTemplate = redisTemplate;
              }
          
              /**
               * 调用 Lua 脚本:根据 key 获取值,若不存在则设置默认值并返回
               */
              public String getOrSetDefault(String key, String defaultValue) {
                  return (String) redisTemplate.execute(
                          LuaScriptLoader.GET_OR_SET_DEFAULT_SHA,
                          Collections.singletonList(key),
                          defaultValue
                  );
              }
          }
          

          五、创建 REST 接口进行测试

          为了方便测试,我们创建一个简单的接口。

          创建控制器类:RedisLuaController.java

          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/redis")
          public class RedisLuaController {
          
              private final RedisLuaService redisLuaService;
          
              public RedisLuaController(RedisLuaService redisLvIutaSsPuaService) {
                  this.redisLuaService = redisLuaService;
              }
          
              @GetMapping("/get-or-set")
              public String getOrDefault(
                      @RequestParam String key,
                      @RequestParam(required = false, defaultValue = "default_value") String defaultValue) {
                  return redisLuaService.getOrSetDefault(key, defaultValue);
              }
          }
          

          六、运行测试

          1. 启动 Redis 服务

          确保你本地或服务器上已经启动了 Redis:

          redis-server
          

          2. 启动 Spring Boot 应用

          使用 IDE 或命令行启动 Spring Boot 项目:

          mvn spring-boot:run
          

          3. 测试访问

          访问如下 URL:

          http://localhost:8080/redis/get-or-set?key=test_lua&defaultValue=hello_redis

          第一次请求:

          Redis 中没有 test_lua 键,会自动设置为 hello_redis,并返回该值。

          第二次请求:

          即使不传 defaultValue,也会返回 hello_redis,因为键已存在。

          七、注意事项

          项目说明
          脚本缓存Redis 会缓存加载过的 Lua 脚本,但重启后失效,需重新加载
          调试困难Lua 脚本不能输出日志,建议先在 Redis CLI 中测试后再集成
          性能考量Lua 脚本是单线程执行的,避免复杂运算
          异常处理在 Java 层应对脚本执行失败做容错处理
          参数传递KEYS 是数组,ARGV 是参数数组,顺序要对应

          八、进阶建议

          • 将所有 Lua 脚本统一管理,使用配置中心或数据库存储
          • 结合 AOP 或拦截器,实现 Lua 脚本调用的自动重试机制
          • 使用 Redisson 等高级库简化 Lua 脚本操作
          • 使用 Springjavascript Cache 抽象层结合 Lua 脚本实现更复杂的缓存策略

          示例结构图

          src/

          ├── main/

          │   ├── java/

          │   │   └── com.example.demo/

          │   │       ├── DemoApplication.java

          │   │       ├── service/

          │   │       │   ├── RedisLuaService.java

          │   │       │   └── LuaScriptLoader.java

          │   │       └── controller/

          │   │           └── RedisLuaController.java

          │   └── resources/

          │       └── lua/

          │           └── get_or_set_default.lua

          └── pom.XML

          总结

          本文详细介绍了如何在 Spring Boot 中调用 Redis 的 Lua 脚本,包括:

          • 添加必要的依赖
          • 编写 Lua 脚本
          • 使用 RedisTemplate 加载和调用脚本
          • 构建完整的调用流程与接口测试

          Lua 脚本非常适合用来实现一些需要原子性的 Redis 操作,是构建高并发系统的重要工具之一。

          到此这篇关于SpringBphpoot集成Redis并调用Lua脚本的示例详解的文章就介绍到这了,更多相关SpringBoot集成Redis调用Lua内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

          0

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          关注公众号