文章目录
- 一、原子性
- 二、Lua
- 2.1 Lua脚本示例
- 2.2 redis-cli使用Lua脚本
- 2.3 jedis使用Lua脚本
- 三、参考
一、原子性
- 原子性是指不可打断的一个完整操作。redis中单个命令是原子的,但是如果期望多个命令组合成一个原子操作,就不行
了,此时需要借助Lua脚本来实现原子性、 - Redis中的弱事务。redis的简单事务,将一组需要一起执行的命令放到multi和exec两个命令之间,其中multi代表事务开始,
exec代表事务结束,不支持事物回滚,不能提供完整的事物特性,使用较少,涉及到的指令如下。
multi、watch、discard、exec
二、Lua
- Lua是一个小巧的脚本语言,由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。
一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。Lua内的代码可以保证原子性,要么全部成功,要么全部失败。 - 在redis中使用Lua脚本的好处:
1.减少网络开销
2.原子操作
3.复用性
2.1 Lua脚本示例
- 如下脚本就是简单的保存address=shenzhen这个键值对,保存成功就返回success,反之返回fail
if redis.call('set',"address","shenzhen") ~= "shenzhen" then
return "success";
else
return "fail";
end
- 使用./redis-cli --eval ./01.lua 执行后发现数据库中保存键值对成功
- 下面是一个传参数的lua脚本的调用方式
if redis.call('set',KEYS[1],KEYS[2]) ~= KEYS[1] then
return "success";
else
return "fail";
end
- 使用./redis-cli --eval ./02.lua hobby basketball 执行后数据库中保存键值对hobby=basketball成功。
其实传参方式很简单,命令后面跟着参数,脚本里面使用KEYS[n]来接受对应的参数,n>0
2.2 redis-cli使用Lua脚本
- redis客户端执行无参lua脚本:./redis-cli -a 123456 --eval ./01.lua
- redis客户端执行有参lua脚本:./redis-cli -a 123456 --eval ./01.lua param1 param2 param3 …
2.3 jedis使用Lua脚本
- Redis代码调用Lua脚本使用eval方法,我们可以看到jedis中有很多重载方法,可以使用字符串和byte数组形式表示Lua和参数,可以批量传参。
public class MyLua {
public static final String REDIS_HOST = "127.0.0.1";
public static final String REDIS_PASSWORD = "Intellifusion@20190108";
public static final int REDIS_PORT = 6379;
public static Jedis jedis = new Jedis(REDIS_HOST);
// static {
// jedis.auth(REDIS_PASSWORD);
// }
public static void main(String[] args) throws InterruptedException, IOException {
byte[] lua = getContent("./02.lua");
//key的字节数组集合
List<byte[]> keyList = new ArrayList<>();
keyList.add("hobby".getBytes());
//值的字节数组集合
List<byte[]> valList = new ArrayList<>();
keyList.add("code".getBytes());
jedis.eval(lua, keyList, valList);
}
//读取文件并以byte数组形式返回
public static byte[] getContent(String filePath) throws IOException {
File file = new File(filePath);
long fileSize = file.length();
if (fileSize > Integer.MAX_VALUE) {
System.out.println("file too big...");
return null;
}
FileInputStream fi = new FileInputStream(file);
byte[] buffer = new byte[(int) fileSize];
int offset = 0;
int numRead = 0;
while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
offset += numRead;
}
// 确保所有数据均被读取
if (offset != buffer.length) {
throw new IOException("Could not completely read file " + file.getName());
}
fi.close();
return buffer;
}
}
- 执行后redis中hobby对应的值就被改变了
三、参考
- [1] Lua 教程