目录
什么是lua
优势
- 减少网络开销:在Lua脚本中可以把多个命令放在同一个脚本中运行
- 原子操作:redis会将整个脚本作为一个整体执行,中间不会被其他命令插入
- 复用性:客户端发送的脚本会永远存储在redis中,这意味着其他客户端可以复用这一脚本来完成同样的逻辑
应用场景
- 游戏开发
- 独立应用脚本
- Web 应用脚本
- 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
- 安全系统,如入侵检测系统
lua安装
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install
执行make linux test时,可能会报下面的错
安装依赖后重新执行即可
[root@xinyeshuaiqi lua]# yum install readline-devel -y
有下面提示信息表示安装成功
[root@xinyeshuaiqi lua]# lua -v
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
lua交互式编程
[root@xinyeshuaiqi lua]# lua -i
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> print("hello world")
hello world
lua脚本式编程
vi hello.lua
print("xinye ")
print("shuaiqi")
执行脚本
[root@xinyeshuaiqi lua]# lua hello.lua
xinye
shuaiqi
lua基础语法
定义变量:
[root@xinyeshuaiqi lua]# lua -i
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> a=1
> print(a)
删除变量:
> a = nil
> print(a)
nil
置为nil即可
判等:
> b=1
> a==b
true
> c =2
> a~=c
true
~= 不等于
> 1=='1'
false
不会自动转型
连接符:
> a..c
12
注释:
单行注释
-- 单行注释
多行注释
--[[ 多行注释 --]]
lua数据类型:
Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。
数据类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。 |
type 函数测试给定变量或者值的类型:
> print(type("Hello world"))
string
> print(type("Hello world"))
string
> print(type(10.4*3))
number
> print(type(print))
function
> print(type(type))
function
> print(type(true))
boolean
> print(type(nil))
nil
> print(type(type(X)))
string
循环:
[root@xinyeshuaiqi lua]# vi test.lua
for i=1,100 do
print(i)
end
while 循环差不多
if-else:
a=5
if(a<10)
then
print("a<10")
else
print("a>=10")
end
print("a=",a)
函数:
function add(a,b)
return a+b
end
print(add(1,3))
lua与redis
Redis 创建了用于与 Lua 环境协作的组件—— 伪客户端,它负责执行 Lua 脚本中的 Redis 命令。
在 Redis 内置的 Lua 解析器中,调用 redis.call() 和 redis.pcall() 函数执行 Redis 的命令
eval的使用:
127.0.0.1:6667> EVAL "return redis.call('SET', 'name', 'xinye')" 0
OK
127.0.0.1:6667> EVAL "return redis.call('GET', 'name')" 0
"xinye"
127.0.0.1:6667> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 haha hehe
OK
127.0.0.1:6667> get haha
"hehe"
KEYS[1]
第一个键值,ARGV[1]
第一个键对应的值
haha hehe
是实际的值
后面跟的numbers,如0或1,表示key的个数
EVALSHA:
127.0.0.1:6667> script load "return redis.call('get','haha')"
"975c5443120508176af91615e70db444745d83bf"
127.0.0.1:6667> evalsha 975c5443120508176af91615e70db444745d83bf 0
"hehe"
Java应用程序使用lua
写一个简单的Spring Boot整合lua的例子
模拟一哈CAS
先写一个脚本:
local current = redis.call('GET', KEYS[1])
if current == ARGV[1]
then redis.call('SET', KEYS[1], ARGV[2])
return true
end
return false
redis配置类:
package pers.wmx.springbootfreemarkerdemo;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author wmx
* @date 2019-12-10
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory ) {
//设置序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
RedisSerializer stringSerializer = new StringRedisSerializer();
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(stringSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(stringSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
加载lua脚本
package pers.wmx.springbootfreemarkerdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
/**
* @author wmx
* @date 2019-12-10
*/
@Component
public class LuaUtil {
@Bean
DefaultRedisScript<Boolean> luaScript() {
DefaultRedisScript<Boolean> luaScript = new DefaultRedisScript<>();
luaScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("test.lua")));
luaScript.setResultType(Boolean.class);
return luaScript;
}
}
写一个单测:
package pers.wmx.springbootfreemarkerdemo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Collections;
/**
* @author wmx
* @date 2019-12-10
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class luaTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
DefaultRedisScript<Boolean> luaScript;
@Test
public void testLua(){
String key = "testLua";
redisTemplate.delete(key);
redisTemplate.opsForValue().set(key, "test CAS");
String s = redisTemplate.opsForValue().get(key).toString();
System.out.println(s);
redisTemplate.execute(luaScript, Collections.singletonList(key), "test CAS", "666");
//redisTemplate.execute(luaScript, Collections.singletonList(key), "test CAS 1", "666");
s = redisTemplate.opsForValue().get(key).toString();
System.out.println(s);
}
}
redisTemplate.execute(luaScript, Collections.singletonList(key), "test CAS 1", "666");
test CAS 1
与 redis存的值test CAS
不同,所以设置新值失败
参考
https://www.runoob.com/lua/lua-tutorial.html
https://www.cnblogs.com/PatrickLiu/p/8391829.html
说点什么
您将是第一位评论人!