今天有个项目需要使用redis,并且有使用脚本的需求。但是因为之前没有写过,所以还有一点点不熟悉,今天记录一下。
原因:
原子操作,redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。
1、创建一个基本的web项目
文件 ->新建 -> 项目,选择spring initializr ,勾选spring web 方便测试,最主要勾选 spring data redis,和下图一样
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、进入服务关闭关闭正在运行的服务器
2、从命令行启动redis
找到redis 在本机的安装路径,我的路径是 C:\Program Files\Redis
打开命令行,输入下面的命令就能启动redis服务器了
redis-server.exe redis.windows.conf
3、在lua脚本中增加打印
redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens)
4、运行代码
调用lua脚本,就可以看到下面的输出了,如果你不想看了,就直接从服务启动redis就好了
注意:正式应用的时候把log 注释掉。
6、总结
今天主要的时间耗费在lua 函数的定义,一直没有搞懂怎么调用,点有背,碰了好多次都没成功。
来源:https://blog.csdn.net/perfect2011/article/details/124392225


猜你喜欢
- 本文实例讲述了Android ActionBar搜索功能用法。分享给大家供大家参考,具体如下:使用ActionBar SearchView时
- 在项目中,有时候会用到领域枚举和DTO枚举的映射和转换。有一个现实的问题是:如果领域枚举项发生变化,而DTO枚举项没有及时更新,这样会造成映
- 本文实例讲述了Android数据持久化之File机制。分享给大家供大家参考,具体如下:在使用Java SE平台开发C/S结构的软件中,Fil
- 本文实例为大家分享了Android RxJava创建操作符Timer的具体代码,供大家参考,具体内容如下之前有写过Android实现倒计时之
- java 引用类型的数据传递的是内存地址java中引用类型的数据,传递的是内存地址,像类,数组,接口,String等等都是引用类型!看下面的
- 一、 添加 maven 依赖<dependency> <groupId>com.google.guava
- 进程间图怎么传递图形buffer写这篇文章的目的:讲解 进程间图怎么传递图形buffer的最近研究图形缓存怎么在进程之间传递的,谷歌了所有的
- 0.写在前面2020-5-18更新这个东西已经是两年前的了,现在问我具体细节我也不是很清楚了,而且现在review两年前的代码感觉写的好烂。
- 前言JDK自带的ZIP操作接口(java.util.zip包,请参看文章末尾的博客链接)并不支持密码,甚至也不支持中文文件名。为了解决ZIP
- 一、概述在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依
- 关于Path之前写的也很多了,例如path绘制线,path绘制一阶,二阶和三阶贝塞尔路径,这些都是path的基本用法。今天我要带大家看的是P
- C++中的动态数组(Dynamic Array)是指动态分配的、可以根据需求动态增长占用内存的数组。为了实现一个动态数组类的封装,我们需要考
- 前面一篇文章已经写了如何搭建一个单机版Redis服务, 那么我们应该怎么在现有的系统中集成进来呢? 由于笔者使用的编程语言是Java, 所以
- 1、结合字节码指令理解Java虚拟机栈和栈帧栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间。每个栈帧中包括局部变量表(Lo
- 面向过程和面向对象的区别面向过程:当事件比较简单的时候,利用面向过程,注重的是事件的具体步骤和过程,注重的是过程中的具体行为,以函数为最小单
- 什么是AOPAOP是Aspect Oriented Programming的缩写,即『面向切面编程』。它和我们平时接触到的OOP都是编程的不
- 1.所有流程的起点是从拨号后按下拨号键开始,此步的代码在/android sourcecode/packages/Contacts/src/
- Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,注意是默认情况下,一个
- 本文实例为大家分享了java实现客房管理系统的具体代码,供大家参考,具体内容如下AddClient.javaimport java.awt.
- 一、JMH vs JMeterJMeter可能是最常用的性能测试工具。它既支持图形界面,也支持命令行,属于黑盒测试的范畴,对非开发人员比较友