首页 > 数据库 >redis初级之Lua脚本

redis初级之Lua脚本

时间:2024-11-28 17:21:36浏览次数:8  
标签:.. -- redis Lua 初级 world hello

Lua脚本

1.简介与用法

简介

​ Lua语言是在1993年由巴西一个大学研究小组发明,其设计目标是作为嵌入式程序移植到其他应用程序,它是由C语言实现的,虽然简单小巧但是功能强大,所以许多应用都选用它作为脚本语言,尤其是在游戏领域,例如大名鼎鼎的暴雪公司将Lua语言引入到“魔兽世界”这款游戏中,Rovio公司将Lua语言作为“愤怒的小鸟”这款火爆游戏的关卡升级引擎,Web服务器Nginx将Lua语言作为扩展,增强自身功能。Redis将Lua作为脚本语言可帮助开发者定制自己的Redis命令,在这之前,必须修改源码。

用法

数据结构及其处理逻辑

Lua语言提供了如下几种数据类型:booleans(布尔)、numbers(数值)、strings(字符串)、tables(表格),和许多高级语言相比相对简单。下面将结合例子对Lua的基本数据类型和逻辑处理进行说明。

(1).字符串
-- 代码示例
local strings val = "hello"
print(val)
--执行结果:hello

print("world")
--执行结果:world

其中local代表val变量是一个局部变量,如果没有local修饰则代表是一个全局变量。

(2).数组

​ 在Lua中,如果要使用类似于数组的功能,可以使用tables类型,下面代码使用定义了一个tables类型的变量myArrays,但和大多数编程语言不同的是,在Lua中的数组下表从1开始计算。

-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
print(myArrays[1])
print(myArrays[2])
print(myArrays[3])
print(myArrays[4])

--执行结果
-- hello
-- world
-- true
-- 88.0

如果想遍历数据可以使用for或者while

for

下面代码会计算1到100的和,关键字for以end作为结束符。

-- 代码示例
local int sum = 0
for i = 1, 100
do
    sum = sum + i
end
print(sum)

--执行结果 5050

如果要遍历数组,则首先需要知道数组的长度,只需要在变量前加一个#号即可

-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
for i=1,#myArrays
do
    print(myArrays[i])
end

--执行结果
-- hello
-- world
-- true
-- 88.0

除此之外Lua还提供了内置函数ipairs,使用 for index, value in ipairs(tables)可以遍历出所有的索引下标和值。

-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
for index, value in ipairs(myArrays)
do
    print(index)
    print(value)
end

--执行结果
-- 1
-- hello
-- 2
-- world
-- 3
-- true
-- 4
-- 88.0
while

下面这段代码同样会计算1到100的和。只不过使用的是while循环,while循环同样以end为结束标记。

-- 代码示例
local int sum = 0
local int i = 1
while i <= 100
do
    sum = sum + i
    i = i + 1
end
print(sum)

--执行结果 5050
if else

要确定数组中存不存在world,有则打印true,没有则打印false,我们可以使用if else语句

-- 代码示例
local tables myArrays = {"hello","world",true,88.0}
local booleans ex = false
for index,value in ipairs(myArrays)
do
    if value == "world"
    then
        ex = true
        break
    end
end
if ex == true
then 
    print("true")
else
    print("false")
end

-- 执行结果 true
(3).哈希

如果要使用类似于哈希的功能,同样可以使用tables类型,例如下面代码定义了一个tables,每个元素包含了key和value,其中strings1..strings2是将两个字符串进行连接。

-- 代码示例
local tables tom = {name = "tom",age = 18,height = 172.5}
print("姓名 : "..tom["name"]..",年龄 : "..tom["age"]..",身高 : "..tom["height"])

--执行结果
-- 姓名 : tom,年龄 : 18,身高 : 172.5

如果要遍历哈希,可以使用Lua的内置函数pairs

-- 代码示例
local tables tom = {name = "tom",age = 18,height = 172.5}
for key,value in pairs(tom)
do
    print(key .. ":" .. value)
end

--执行结果
-- height:172.5
-- age:18
-- name:tom

函数定义

​ 在Lua中,函数以function开头,以end结尾,funcName是函数名,中间部分是函数体。

-- function funcName()
--     ···
-- end

-- 例如写一个contact方法用来拼接两个字符串
function contact (str1 , str2)
    return str1 .." ".. str2
end
print(contact("hello ","world"))

--执行结果 hello world

2.Redis与Lua

在Redis中使用Lua

在Redis中执行Lua脚本有两种方法:eval 和 evalsha

(1) eval

eval 脚本内容 key个数 key列表 参数列表

下面例子使用了key列表和参数列表来为Lua脚本提供更多的灵活性:

> eval 'return "hello ".. KEYS[1] .. " " .. ARGV[1]' 1 redis world
"hello redis world"

此时KEYS[1] = redis,ARGV[1] = world,所以最终的打印结果为 hello redis world

注意:KEYS 和 ARGV 一定要大写否则会报错,如下

> eval 'return "hello ".. keys[1] .. " " .. argv[1]' 1 redis world
"ERR Error running script (call to f_9f158bb8946915295cd6c488611b5004b5bf66c9): @user_script:1: user_script:1: Script attempted to access nonexistent global variable 'keys'"

> eval 'return "hello ".. KEYS[1] .. " " .. argv[1]' 1 redis world
"ERR Error running script (call to f_6248f0862bc574fb60782a2d632d7db773e16286): @user_script:1: user_script:1: Script attempted to access nonexistent global variable 'argv'"

如果不需要传KEYS或者ARGVS可以进行以下操作:

# 不传KEYS
> eval 'return "hello ".. ARGV[1] .. " " .. ARGV[2]' 0 redis world
"hello redis world"

# 不传ARGVS
> eval 'return "hello ".. KEYS[1] .. " " .. KEYS[2]' 2 redis world
"hello redis world"

如果Lua脚本过长,还可以直接使用redis-cli --eval 直接执行Lua脚本文件。

eval命令和--eval参数本质是一样的,客户端如果想执行Lua脚本,首先在客户端编写好Lua脚本代码,然后把脚本作为字符串发送给服务器,服务器端会将执行结果返回给客户端。

注意:这里的参数是需要使用逗号隔开的,逗号左右两边都需要有一个空格,没有参数则不填。

[root@xxx src]# cat /root/myredis/script/contactStr.lua 
return ARGV[1].." "..ARGV[2]
[root@xxx src]# redis-cli -a xxx --eval /root/myredis/script/contactStr.lua , hello world
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"hello world"

整个过程如图所示

(2) evalsha

​ 除了使用eval,Redis还提供了evalsha命令来执行Lua脚本。首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和,evalsha命令使用SHA1作为参数可以直接执行对应的Lua脚本,避免每次发送Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到了服用。

加载脚本:

​ script load命令可以将脚本内容加载到Redis内存中,例如下面将contactStr.lua脚本加载到Redis中,得到SHA1为:9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34

# 代码示例
[root@xxx src]# redis-cli -a xxx script load "$(cat /root/myredis/script/contactStr.lua)"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34"
执行脚本:

​ evalsha的使用方法如下,参数使用SHA1值,执行逻辑和eval一致。

evalsha 脚本SHA1值 key个数 key列表 参数列表

# 代码示例
[root@xxx src]# redis-cli -a xxx evalsha 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34 0 hello world
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"hello world"

Lua的Redis API

​ Lua可以使用redis.call函数实现对Redis的访问,例如下面的代码是Lua使用redis.call调用了Redis的set和get操作:

-- 代码示例
redis.call("set","hello","world")
redis.call("get","hello")

​ 放在Redis的执行效果如下:

# 代码示例
> set hello world
"OK"

> eval 'return redis.call("get",KEYS[1])' 1 hello
"world"

​ 除此之外Lua还可以使用redis.pcall函数实现对Redis的调用,redis.call和redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返回错误,而redis.pcall会忽略错误继续执行脚本。

3.Redis如何管理Lua

​ Redis提供了4个命令实现对Lua脚本的管理。

(1) script load

​ 此命令用于将Lua脚本加载到Redis内存中

# 代码示例
[root@xxx src]# redis-cli -a xxx script load "$(cat /root/myredis/script/contactStr.lua)"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
"9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34"

(2) script exists

​ 此命令用于判断sha1是否已经加载到Redis内存中

# 代码示例
> script exists 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34
1) "1"

因为这里的参数可以填多个,返回值为被加载到Redis内存中的Lua脚本个数。

(3) script flush

​ 此命令用于清除Redis内存已经加载的所有Lua脚本。

# 代码示例
> script flush
"OK"

> script exists 9295ec8b57e8e4d0a3e89f6cb3ab5b225d2bcb34
1) "0"

(4) script kill

此命令用于杀掉正在执行的Lua脚本。如果Lua脚本比较耗时,甚至Lua脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或者外部进行干预将其结束。

标签:..,--,redis,Lua,初级,world,hello
From: https://www.cnblogs.com/lixiuxiu/p/18574681

相关文章

  • 多线程判断redis key导致Java hep space内存溢出
     线上经常发现报如下错误,后来发现rootcause是selectConfigitemforinstanceMap这个方法会查出几十万的结果集然后json压缩解压,写map等等操作,但是这个selectConfigitemforinstanceMap方法被很多地方调用到了,导致极有可能多线程同时都在查出几十万的结果集然后json压缩解压,写map等......
  • redis安装
    一、通用方式要在Linux上安装Redis,可以按照以下步骤进行操作:1.打开终端,使用以下命令下载Redis的压缩包:1wgethttp://download.redis.io/releases/redis-x.x.x.tar.gz注意将"x.x.x"替换为你想要下载的Redis版本号。2.解压下载的压缩包:1tar......
  • redis初级之事务
    事务​ 事务表示一组动作,要么全部执行,要么全不执行。例如在抖音上用户A关注了用户B,在用户A的关注的人中要添加用户B,在用户B的粉丝中要添加用户A,这些操作要么全部执行,要不全不执行,否则就会造成数据不同步的问题,比如用户A关注了用户B,用户A关注的人中有用户B,但是用户B的粉丝中并没有......
  • Redis【1】- 如何阅读 Redis源码
    1Redis的简介Redis实际上是简称,全称为RemoteDictionaryServer(远程字典服务器),由SalvatoreSanfilippo写的高性能key-value存储系统,其完全开源免费,遵守BSD协议。Redis与其他key-value缓存产品(如memcache)有以下几个特点。数据持久化:可以将内存中的数据保存在磁......
  • 5、Redis缓存设计最佳实践
    缓存穿透缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。造成缓存穿透的基本原因有两个:第一,自身业务......
  • 6、Redis开发规范与性能优化
    键值设计key设计可读性与管理性,以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id简洁性,保证语义的前提下,控制key的长度不要包含特殊字符value设计拒绝bigkey在Redis中,一个字符串最大512MB,一个二级数据结构(例如hash、list、set、zset)可以存储......
  • 3、Redis主从、哨兵与集群架构
    Redis主从架构主从搭建步骤1、复制一份redis.conf文件2、将相关配置修改为如下值:port6380pidfile/var/run/redis_6380.pid#把pid进程号写入pidfile配置的文件logfile"6380.log"dir/usr/local/redis-5.0.3/data/6380#指定数据存放目录#需要注释掉bind#......
  • redis锁等待随机毫秒数拦截和程序自动过期双重机制
    redis锁等待随机毫秒数拦截和程序自动过期双重机制上一个操作加了锁,需要等待上一个操作执行完毕之后,才允许当前操作执行,所以当前操作需要执行锁等待处理。 packagecom.example.core.mydemo.javaDemo;importjava.time.LocalDateTime;publicclassRandomTest{publ......
  • redis锁和等待锁随机毫秒数解决程序调用方控制执行的先后顺序,避免并发操作造成的数据
    redis锁和等待锁随机毫秒数解决程序调用方控制执行的先后顺序,避免并发操作造成的数据不一致现象:向第三方服务调用接口,比如更换商品换货,需要先取消,然后再新增操作。同时可能存在修改并发操作(同时操作换货和修改操作),在取消和新增的间隙中做了修改操作,引起脏数据等数据不一致的问题......
  • mongodb/redis/neo4j 如何自己打造一个 web 数据库可视化客户端?
    随笔从千万粉丝“何同学”抄袭开源项目说起,为何纯技术死路一条?数据源的统一与拆分监控报警系统的指标、规则与执行闭环我们的系统应该配置哪些监控报警项?监控报警系统如何实现自监控?java老矣,尚能饭否?一骑红尘妃子笑,无人知是荔枝来!张居正的考成法,对我们有何参考价值?mon......