一、简介
1、什么是Lua
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 是巴西里约热内卢天主教大学里的一个研究小组于 1993 年开发的。
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
2、Lua 特性
- 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
- 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
- 其它特性
- 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
- 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
- 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
- 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等
3、在线调试工具
Lua在线调试工具: https://wiki.luatos.com/_static/luatos-emulator/lua.html
测试:
-- 打印内容
print('Hello,Lua!')
二、变量类型
-- 在lua中声明变量可以使用以下写法
num1 = 1;
-- 上述代码声明的是一个全局变量,可以使用 local 关键字声明一个局部变量
local num2 = 1;
1、nil
nil
类型就是类似于其它语言的null
类型,在Lua中没有被声明的都是nil
类型
-- 未声明过a变量,打印直接是nil
print(a)
2、number
number
类型是数值型 包括浮点数
-- 声明一个number类型变量
local num1 = 10
3、字符串
string
类型,与java一样支持转义字符\n
换行字符 \t
空格
字符串是若干封装在双括号(“)或单括号(‘)内的字符。字符串示例如下:
- “fish”
- ‘fish’
- “5467”
- “a line”
-- 双引号声明
local str1 = "abcdefg"
-- 单引号声明
local str2 = 'abcdefg'
-- 多行文本声明,打印原始内容 转义字符不会被转换
local str3 = [[
abcdefg\dasdc\dn
]]
字符串拼接
local str1 = "Hello,"
local str2 = "Lua"
print(str1..str2)
-- 输出内容Hello,Lua
注意:与Java不同的是这里的字符串拼接使用的是..
而不是+
获取字符串长度
local str1 = "abcdefg"
print(#str1) -- 输出str1字符串的长度
类型转换
-- 字符串转number
local num1 = tonumber('10') -- 结果为数值类型10
-- number转字符串
local str1 = tostring(10) -- 结果为字符串类型10
-- 不合法转换
local str = tonumber('abc') -- 结果转换为nil
4、boolean
boolean类型有两种值:true和false
-- 声明一个bool类型
local flag = true
注意:在lua中不等于是用 ~=来标识 而不是用 !=
lua也支持 与或非 等操作
5、函数
类似于Java中的方法
-- 声明函数语法
function 函数名(参数)
-- 主体
-- return 返回值
end
6、table
类似于Java中的集合,与Java不同的是下标是从1
开始的,而不是从0
-- 声明table
local tb = {10,"jiabin",{},function() end}
-- 打印jiabin
print(tb[2])
-- 打印不存在的下标
print(tb[8]) -- 输出结果nil
-- 赋值
tb[5] = "2022-7-6" -- 为下标5赋值
print(#tb) -- 打印table的长度
-- 插入元素
table.insert(tb,"hahah") --在最后一位插入元素
table.insert(tb,2,"hahah") --在table的第2位插入元素,后面的元素会被往后挤
-- 移除元素
table.remove(tb.2) -- 移除下标为2的元素
local abc = table.remove(tb.2) -- 存储被移除的元素
使用字符串为下标
local student = {
stuId = 1,
stuName = "jiabin",
stuAge = "18"
}
print(student['stuName']) -- 输出jiabin
print(student.stuName) -- 输出jiabin
五、分支判断
注意:在Lua脚本中,0代表真
1、普通if
-- 普通判断
if 条件 then
-- 主体
end
2、if-else
-- if else
if 条件 then
-- 主体
else
-- 主体
end
3、多分支
-- 多分支
if 条件 then
-- 主体
elseif 条件 then
-- 主体
else
-- 主体
end
六、循环
1、for循环
-- for
for 变量=初始值,结束值,步长 do
-- 主体
end
-- 循环输出10次
for i=1,10 do
print(i)
end
-- 倒叙排序
for i=10,1,-1 do
print(i)
end
2、while循环
-- while
local num = 10
while num > 1 do
print(num)
num = num - 1 -- Lua中不支持自减:n-=1
end
七、使用Lua操作Redis
1、分布式锁
-
创建maven项目导入依赖
-
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.2.1.RELEASE</version> </dependency> </dependencies>
-
-
创建配置文件
【application.properteis】
-
# 指定端口号 server.port=8199 # 连接redis spring.redis.host=192.168.171.138 spring.redis.port=6379
-
-
创建配置类
【LuaRedisConfig:注意正确指定lua脚本位置】
-
/** * @Author 嘉宾 * @Data 2022/7/6 20:37 * @Version 1.0 * @Description 用于声明lua */ @Configuration public class LuaRedisConfig { /** * 分布式锁脚本 * @return */ @Bean public DefaultRedisScript<Long> lockRedisScript() { // 定义DefaultRedisScript DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); // 指定lua脚本路径 redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua"))); // 设置返回类型 redisScript.setResultType(Long.class); return redisScript; // 返回lua脚本内容 } }
-
-
在
resources
目录下创建目录script
目录在其目录下创建Lua脚本文件-
local lockUUID = KEYS[1] -- 锁中的uuid值 local uuid = ARGV[1] -- 用户的uuid值 -- 判断锁中的uuid是否与用户的uuid相等 if redis.call('get',lockUUID) == uuid then return redis.call('del',lockUUID) -- 相等的话就释放锁 else -- 未获得锁 return 0 -- 返回0 end
-
-
创建controller编写接口
-
/** * @Author 嘉宾 * @Data 2022/7/6 20:39 * @Version 1.0 * @Description */ @RestController @RequestMapping("/lua") public class TestController { @Autowired private StringRedisTemplate stringRedisTemplate; @Resource private DefaultRedisScript<Boolean> lockRedisScript; // 分布式锁脚本 /** * 计数 * @return */ @GetMapping("/getLock") public String getLock(){ // 生成UUID String uuid = UUID.randomUUID().toString(); // 1、获取锁:true得到锁,false未得到 Boolean redisLock = stringRedisTemplate.opsForValue().setIfAbsent("lock_redis", uuid,3, TimeUnit.SECONDS); // 判断是否得到锁 if(redisLock){ // ...自己的业务 String value = stringRedisTemplate.opsForValue().get("num"); if(StringUtils.isEmpty(value)){ stringRedisTemplate.opsForValue().set("num","1"); } int num = Integer.parseInt(value + "") + 1; stringRedisTemplate.opsForValue().set("num",num+""); // 获取锁中的内容 String lockUUID = stringRedisTemplate.opsForValue().get("lock_redis"); // 使用Lua脚本比较 // 指定参数 List<String> keys = Arrays.asList(lockUUID); stringRedisTemplate.execute(lockRedisScript,keys,uuid); return "success"+num; }else{ // // 每隔0.1秒再获取一次 // try { // Thread.sleep(100); // this.getLock(); // }catch (InterruptedException e){ // e.printStackTrace(); // } return "miss"; } } }
-
-
测试 访问接口 localhost:8199/lua/getLock
- 返回
success:访问量
代表得到锁并进行计数 - 返回
miss
代表 未得到锁
- 返回