springboot中使用redis并且执行调试lua脚本

作者:香菜_香菜 时间:2022-02-15 08:49:52 

今天有个项目需要使用redis,并且有使用脚本的需求。但是因为之前没有写过,所以还有一点点不熟悉,今天记录一下。

原因:

原子操作,redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。

1、创建一个基本的web项目

文件 ->新建 -> 项目,选择spring initializr ,勾选spring web 方便测试,最主要勾选 spring data redis,和下图一样

springboot中使用redis并且执行调试lua脚本

2、配置redis

因为我是为了测试redis,所以直接使用的本地的redis,你可以替换成application.yaml,或者使用环境变量替换。

#Redis服务器ip
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379

注: 你不配置的话默认值就是上面的

3、测试redis 的lua脚本

先写个能方便测试的接口,因为我为了测试lua 的脚本执行,所以就没讲什么设计,直接验证脚本

这里要做的就是删除过期的key,同时移除hash中的key

package com.pdool.main;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

@RestController
public class TestController {
   @Autowired
   private StringRedisTemplate redisTemplate;

@RequestMapping("test")
   public String test() {
       System.out.println("xxxxxxxxxxxxxx");
       try {
           //调用lua脚本并执行
           DefaultRedisScript<Void> redisScript = new DefaultRedisScript<>();
           redisScript.setResultType(Void.class);//返回类型是Long
           //lua文件存放在resources目录下的redis文件夹内
           Set<String> webApiRequestSet = new HashSet<>();
           webApiRequestSet.add("aa");
           webApiRequestSet.add("bb");

Set<String> webWebsocketRequestSet = new HashSet<>();

String shortHashKey = "abc";
           String longHashKey = "def";
           String delShortKeys = webApiRequestSet.stream().map((requestId) -> shortHashKey + ":" + requestId).collect(Collectors.joining(";"));
           String delLongKeys = webWebsocketRequestSet.stream().map((requestId) -> longHashKey + ":" + requestId).collect(Collectors.joining(";"));
           List<String> keys = Arrays.asList(shortHashKey, longHashKey);

redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/clear-local-key.lua")));
           redisTemplate.execute(redisScript, keys, delShortKeys, delLongKeys);
       } catch (Exception e) {
           e.printStackTrace();
       }
       return "sssssssss";
   }
}

再来看下lua脚本,这东西花了我不少的时间

local short_hash_key = KEYS[1];
local long_hash_key = KEYS[2];
local del_short_hash_keys = ARGV[1];
local del_long_hash_keys = ARGV[2];

local function tt_split(str,reps )
         local resultStrList = {}
         string.gsub(str,'[^'..reps..']+',function ( w )
             table.insert(resultStrList,w)
         end)
         return resultStrList
     end
local del_short_key_list= tt_split(del_short_hash_keys,";")
for i = 1, #del_short_key_list do
   local del_key = del_short_key_list[i];
   redis.call("DEL", del_key)
   redis.call("HDEL", short_hash_key, del_key)
end

local del_long_key_list = tt_split(del_long_hash_keys,";")
for i = 1, #del_long_key_list do
   local del_key = del_long_key_list[i];
   redis.call("DEL", del_key)
   redis.call("HDEL", long_hash_key, del_key)
end

4、技术点

1、redis 传参可以有两个全局变量,一个KEYS,一个是ARGV

2、redis执行的lua 不可以有全局变量,因为会污染环境,所以这里的function 是local

3、lua没有线程的字符串拆分函数,上面的函数是我找些unity的同学从项目中扒出来的

4、lua 列表的下标从1 开始的

5、redis中执行的lua 是 事务性的

6、lua 会阻塞线程,如果脚本太耗时会卡主服务器

5、调试方式

调试lua脚本是真的费劲,因为在redis desktop manage中不太好测试,下面说下怎么测试,如果你本机安装了redis。

1、进入服务关闭关闭正在运行的服务器

springboot中使用redis并且执行调试lua脚本

2、从命令行启动redis

找到redis 在本机的安装路径,我的路径是 C:\Program Files\Redis

打开命令行,输入下面的命令就能启动redis服务器了

redis-server.exe redis.windows.conf

springboot中使用redis并且执行调试lua脚本

3、在lua脚本中增加打印

redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)

4、运行代码

调用lua脚本,就可以看到下面的输出了,如果你不想看了,就直接从服务启动redis就好了

注意:正式应用的时候把log 注释掉。

springboot中使用redis并且执行调试lua脚本

6、总结

今天主要的时间耗费在lua 函数的定义,一直没有搞懂怎么调用,点有背,碰了好多次都没成功。

来源:https://blog.csdn.net/perfect2011/article/details/124392225

标签:springboot,redis,调试,lua
0
投稿

猜你喜欢

  • Android PopupWindow 点击外面取消实现代码

    2022-02-04 20:52:05
  • 使用Java实现简单串口通信

    2022-07-27 14:48:52
  • Java ShutdownHook原理详解

    2023-11-10 21:30:36
  • Java京东面试题之为什么HashMap线程不安全

    2022-12-06 07:20:02
  • log4j2日志异步打印(实例讲解)

    2023-11-12 09:02:13
  • Java Swing组件布局管理器之FlowLayout(流式布局)入门教程

    2021-11-08 05:33:06
  • MyBatis环境资源配置实现代码详解

    2023-08-05 08:59:02
  • C#加密知识整合 (AES,MD5,RSA,SHA256)

    2023-07-19 09:09:13
  • Android开发仿映客送礼物效果

    2023-03-24 01:11:12
  • maven多个plugin相同phase的执行顺序

    2021-07-07 10:33:34
  • 详谈Java中net.sf.json包关于JSON与对象互转的坑

    2023-03-02 12:38:31
  • Java实现有限状态机的推荐方案分享

    2022-01-07 15:54:27
  • Java的Spring框架中bean的继承与内部bean的注入

    2023-06-17 18:50:44
  • java中BigDecimal和0比较的示例代码

    2022-07-05 04:58:18
  • java 内部类(匿名类,匿名对象,静态内部类)详解及实例

    2022-09-25 11:20:16
  • java实现推箱子小游戏

    2023-02-09 04:57:52
  • C#实现猜数字游戏

    2021-11-16 07:29:58
  • spring中的FactoryBean代码示例

    2023-11-11 18:37:20
  • Java通过jersey实现客户端图片上传示例

    2022-09-17 15:44:24
  • c# wpf使用GMap.NET类库,实现地图轨迹回放

    2023-04-20 06:46:27
  • asp之家 软件编程 m.aspxhome.com