redis eval表达式1
Lua(发音类似 Loo-ah)是一门轻量级脚本语言,由巴西里约热内卢天主教大学开发。Redis 之所以选择 Lua,是因为它语法简单、运行速度快、容易嵌入到其他程序中。
很多 Java 开发者接触 Lua,都是从 Redis 的 EVAL 开始的,所以这里我从 Java 开发者的视角 来介绍 Lua 的常用语法。
1. Lua 的基本特点
动态类型
解释执行
语法简单
支持函数式编程
支持面向过程编程
只有一种复杂数据结构:Table
Lua 类似于:
Java + JavaScript 的结合体
例如:
Java:
int a = 10;
Lua:
a = 10
不需要定义类型。
2. 变量定义
Lua 默认变量是全局变量。
name = "Tom"
print(name)
输出:
Tom
局部变量:
local age = 18
print(age)
Redis Lua 中几乎都会写:
local value = redis.call(...)
避免污染全局变量。
3. 数据类型
Lua 主要有:
nil
boolean
number
string
function
table
userdata
thread
Redis Lua 常见的是:
local a = 10
local b = true
local c = "hello"
local d = {}
nil
类似 Java 的 null
local a
print(a)
输出:
nil
number
Lua 中整数和小数都属于 number。
local a = 100
local b = 3.14
string
local name = "Jack"
local city = 'Beijing'
拼接:
print(name .. city)
输出:
JackBeijing
注意:
Lua 使用:
..
而不是:
+
4. 判断语句
Java:
if(age > 18){
...
}else{
...
}
Lua:
if age > 18 then
print("adult")
else
print("child")
end
Redis 最常见:
if redis.call('EXISTS', KEYS[1]) == 1 then
return 1
else
return 0
end
5. 循环
while
local i = 1
while i <= 5 do
print(i)
i = i + 1
end
for
Java:
for(int i=1;i<=5;i++)
Lua:
for i = 1,5 do
print(i)
end
输出:
1
2
3
4
5
步长:
for i = 1,10,2 do
print(i)
end
输出:
1
3
5
7
9
6. Table(最重要)
Lua 中没有:
List
Map
Set
对象
这些都是 Table 实现的。
当数组用
local arr = {1,2,3}
print(arr[1])
输出:
1
注意:
Lua 下标从 1 开始。
不是 Java 的:
0
遍历:
for i,v in ipairs(arr) do
print(i,v)
end
输出:
1 1
2 2
3 3
当 Map 用
local user = {}
user["name"] = "Tom"
user["age"] = 18
访问:
print(user["name"])
或者:
print(user.name)
输出:
Tom
模拟对象
local person = {
name = "Jack",
age = 18
}
print(person.name)
输出:
Jack
7. 函数
定义:
function add(a,b)
return a+b
end
调用:
print(add(1,2))
输出:
3
匿名函数:
local f = function(a,b)
return a+b
end
8. 逻辑运算
and
or
not
类似 Java:
&&
||
!
例如:
if age > 18 and age < 60 then
print("成年人")
end
9. Redis Lua 中的特殊变量
执行:
EVAL script 2 key1 key2 arg1 arg2
Lua 中:
KEYS[1] = key1
KEYS[2] = key2
ARGV[1] = arg1
ARGV[2] = arg2
例如:
EVAL "
return KEYS[1] .. ':' .. ARGV[1]
" 1 user Tom
结果:
user:Tom
10. Redis Lua 常见写法
判断并删除
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
end
return 0
扣减库存
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
redis.call('DECR', KEYS[1])
return 1
end
return 0
限流
local count = redis.call('INCR', KEYS[1])
if count == 1 then
redis.call('EXPIRE', KEYS[1], ARGV[1])
end
if count > tonumber(ARGV[2]) then
return 0
end
return 1
11. Lua 和 Java 的对照
| Java | Lua |
|---|---|
int a=1; |
a=1 |
String s="abc"; |
s="abc" |
null |
nil |
&& |
and |
|| |
or |
! |
not |
+ 字符串拼接 |
.. |
List |
Table |
Map |
Table |
| 数组下标 0 开始 | 数组下标 1 开始 |
for(int i=0;i<n;i++) |
for i=1,n do |
12. Java 工程师学习 Lua 的重点
如果你的目标只是为了使用 Redis Lua,那么实际上只需要掌握下面这些内容:
✓ local
✓ if ... then ... end
✓ tonumber()
✓ tostring()
✓ Table 的基本使用
✓ KEYS 和 ARGV
✓ redis.call()
✓ return
大概 1~2 小时就足够应付 90% 的 Redis Lua 场景。
例如下面这个分布式锁释放脚本:
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
else
return 0
end
如果你能看懂这段代码,就已经具备在 Redis 中编写 Lua 脚本的能力了。
对于 Java 开发者来说,可以把 Lua 理解为:
一种运行在 Redis 内部、用于把多个 Redis 命令组合成原子操作的小型脚本语言。
浙公网安备 33010602011771号