Maison  >  Article  >  base de données  >  Comment utiliser le script Lua dans l'écosystème Java/Redis

Comment utiliser le script Lua dans l'écosystème Java/Redis

WBOY
WBOYavant
2023-06-02 22:41:081381parcourir

1. Installez LUA

Il est très simple d'installer LUA sur Mac, utilisez simplement les commandes associées à brew brew相关命令;

brew install lua

Comment utiliser le script Lua dans lécosystème Java/Redis

使用lua -v命令可以看到lua已经安装完毕。

1)简单使用

创建一个test.lua文件,内容为:

Comment utiliser le script Lua dans lécosystème Java/Redis

执行命令:

lua test.lua

输出为:

Comment utiliser le script Lua dans lécosystème Java/Redis

二、lua语法简介

Lua 提供了交互式编程和脚本式编程:

  • 交互式编程:直接在命令行中输入语法,可以立即执行并查看到执行效果。

  • 脚本是编程:编写脚本文件,然后再执行。

1、注释

lua提供两种注释方式:单行注释和多行注释

1)单行注释

使用两个减号;

--

2)多行注释
--[[
 多行注释
 多行注释
 --]]

2、关键字

下列为 Lua 的保留关键字,和Java一样 保留关键字不能作为常量或变量。

Comment utiliser le script Lua dans lécosystème Java/Redis

3、变量

默认的情况下,定义一个变量都是全局变量;如果要用局部变量 需要声明为local

1)全局变量

全局变量不需要声明,给一个变量赋值后便创建了这个全局变量;

访问一个没有初始化的全局变量也不会出错,只不过会得到结果:nil

Comment utiliser le script Lua dans lécosystème Java/Redis

只要将变量赋值为nil,就可以删除全局变量;换句话说,当且仅当变量为nil时,该变量不存在。

Comment utiliser le script Lua dans lécosystème Java/Redis

此外,一般以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。

2)局部变量
-- 局部变量赋值
local b=2

4、数据类型

Lua 是一个动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。

Comment utiliser le script Lua dans lécosystème Java/Redis

1)Lua数组

在Lua 数组中,索引值是从 1 开始,可以指定为从 0 开始。

Comment utiliser le script Lua dans lécosystème Java/Redis

2)字符串操作
  • .. 连接两个字符串;

  • string.sub() 用于截取字符串;

string.sub(s, i [, j])
  • s:要截取的字符串;

  • i:截取开始位置;

  • j:截取结束位置,默认为 -1,最后一个字符;

string.find() 用于字符串查找

string.find (str, substr, [init, [plain]])
  • 在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。

  • init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。

  • plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用正则模式匹配。

5、if-else

条件表达式结果可以是任何值,Lua认为false和nil为假,true和非nil为真。

整体的if-else结构和我们使用的高级语言(Java、GO)类似,区别在于:LUA中的if()表达式满足之后想要做一些其余逻辑,需要紧跟then,并且流程控制以end

if(xxx) then
    print("xxx")
else if(xx) then
    print("xx")
else
   print("x")
end

Java Ecosystem/Comment utiliser le script Lua dans Redis

Utilisez la commande lua -v pour voir que lua a été installé.
1) Utilisez simplement

pour créer un fichier test.lua avec le contenu suivant :

Comment utiliser le script Lua dans Java ecology/Redis

Exécuter la commande :

for var=exp1,exp2,exp3 do  
    <执行体>  
end

Le résultat est : Comment utiliser le script Lua dans lécosystème Java/Redis

🎜Comment utiliser les scripts Lua dans Java ecology/Redis🎜🎜2. Introduction à la syntaxe Lua🎜🎜Lua propose une programmation interactive et une programmation scriptée :🎜
  • 🎜Programmation interactive : saisissez la syntaxe directement dans la ligne de commande, vous pouvez l'exécuter immédiatement et voir l'effet d'exécution. 🎜
  • 🎜Le script, c'est la programmation : écrivez un fichier de script puis exécutez-le. 🎜
  • 🎜1. Commentaires🎜🎜lua propose deux méthodes de commentaires : les commentaires sur une seule ligne et les commentaires sur plusieurs lignes🎜🎜1) Les commentaires sur une seule ligne🎜🎜utilisent deux signes moins ;🎜🎜 --🎜🎜2) Commentaires multilignes🎜<pre class="brush:java;">--打印数组a的所有值 a = {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;} for i, v in ipairs(a) do print(i, v) end</pre>🎜2. Mots-clés🎜🎜Les mots-clés suivants sont réservés à Lua. Comme Java, les mots-clés réservés ne peuvent pas être utilisés comme constantes ou variables. 🎜🎜<img src="https://img.php.cn/upload/article/000/887/227/168571687129252.png" alt="Comment utiliser le script Lua dans Java ecology/Redis">🎜🎜3 . Variables 🎜🎜Par défaut, une variable définie est une variable globale ; si vous souhaitez utiliser une variable locale, elle doit être déclarée comme <code>local 🎜🎜1) Les variables globales 🎜🎜Les variables globales le font. pas besoin d'être déclarée, donnez une variable Cette variable globale est créée après l'affectation ; 🎜🎜Il n'y aura pas d'erreur lors de l'accès à une variable globale non initialisée, mais le résultat sera : nil🎜🎜Java Ecosystem/Comment utiliser le script Lua dans Redis🎜🎜Tant que la variable est affectée à nil, le global la variable peut être supprimée ; autrement dit, si et seulement si la variable Lorsqu'elle est nulle, la variable n'existe pas. 🎜🎜Comment utiliser le script Lua dans Java ecology/Redis🎜🎜🎜 De plus, généralement les noms commençant par un trait de soulignement suivi d'une chaîne de lettres majuscules (comme _VERSION) sont réservés aux variables globales internes de Lua. 🎜🎜🎜2) Variables locales🎜
    while(condition)
    do
       statements
    end
    🎜4. Types de données🎜🎜Lua est un langage typé dynamiquement. Les variables n'ont pas besoin d'être saisies, seules les variables doivent se voir attribuer des valeurs. Les valeurs peuvent être stockées dans des variables, transmises comme arguments ou renvoyées comme résultats. 🎜🎜Il existe 8 types de base dans Lua : nul, booléen, nombre, chaîne, données utilisateur, fonction, thread et table. 🎜🎜Comment utiliser le script Lua dans Java Ecology/Redis🎜🎜1 ) Tableau Lua🎜🎜Dans le tableau Lua, la valeur d'index commence à 1 et peut être spécifiée pour commencer à 0. 🎜🎜Comment utiliser le script Lua dans Java ecology/Redis🎜🎜2 ) Opérations sur les chaînes 🎜
    • 🎜.. Concaténer deux chaînes 🎜
    • 🎜string.sub () est utilisé pour intercepter les chaînes ; 🎜
    --[[ 函数返回两个值的最大值 --]]
    function max(num1, num2)
       if (num1 > num2) then
          result = num1;
       else
          result = num2;
       end
       return result; 
    end
    -- 调用函数
    print("两值比较最大值为 ",max(10,4))
    print("两值比较最大值为 ",max(5,6))
    • 🎜s : la chaîne à intercepter 🎜
    • 🎜i : position de début de l'interception ; 🎜
    • 🎜j : position de fin de l'interception, la valeur par défaut est -1, le dernier caractère ; 🎜
    🎜string find(. ) est utilisé pour la recherche de chaîne🎜
    <dependency>
        <groupId>org.luaj</groupId>
        <artifactId>luaj-jse</artifactId>
        <version>3.0.1</version>
    </dependency>
    • 🎜Recherchez le contenu spécifié substr dans une chaîne cible spécifiée str, si une correspondance est trouvée sous-chaîne, le début l'index et l'index de fin de la sous-chaîne seront renvoyés s'ils n'existent pas, nul sera renvoyé. 🎜
    • 🎜init précise la position de départ de la recherche, la valeur par défaut est 1, il peut s'agir d'un nombre négatif, indiquant le nombre de caractères en comptant de l'arrière vers l'avant. 🎜
    • 🎜plain indique s'il faut utiliser le mode simple, la valeur par défaut est false, true effectue uniquement une recherche simple de sous-chaînes, false indique l'utilisation d'une correspondance de modèles régulière. 🎜
    🎜5. if-else🎜🎜Le résultat de l'expression conditionnelle peut être n'importe quelle valeur. Lua considère que faux et nul sont faux, et vrai et non nul sont vrais. 🎜🎜La structure globale if-else est similaire aux langages de haut niveau que nous utilisons (Java, GO). La différence est que si vous souhaitez appliquer une autre logique une fois l'expression if() dans LUA satisfaite, vous doit suivre then, et le contrôle de flux se termine par end. 🎜
    package com.saint.base.lua;
    
    import org.luaj.vm2.Globals;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    public class LuaString {
        public static void main(String[] args) {
            String luaStr = "print &#39;Saint is best man&#39;";
            Globals globals = JsePlatform.standardGlobals();
            LuaValue luaValue = globals.load(luaStr);
            luaValue.call();
        }
    }
    🎜6. Loop🎜🎜1) for loop🎜🎜Il existe deux grandes catégories d'instructions for dans le langage de programmation Lua : array for loop et générique for loop🎜🎜1> 🎜 var passe de exp1 à exp2. Chaque changement incrémente var avec exp3 comme taille de pas et exécute le "corps d'exécution" une fois. exp3 est facultatif et la valeur par défaut est 1 s'il n'est pas spécifié. 🎜🎜🎜🎜

    2> 泛型for循环

    通过一个迭代器函数来遍历所有值,类似 java 中的 foreach 语句;

    语法格式:

    --打印数组a的所有值  
    a = {"one", "two", "three"}
    for i, v in ipairs(a) do
        print(i, v)
    end
    • i 是数组索引值,v 是对应索引的数组元素值。

    • ipairs是Lua提供的一个迭代器函数,用来迭代数组。

    Comment utiliser le script Lua dans lécosystème Java/Redis

    2)while循环

    while 循环语句在判断条件为 true 时会重复执行循环体语句。

    语法格式:

    while(condition)
    do
       statements
    end
    • statements(循环体语句) 可以是一条或多条语句,condition(条件) 可以是任意表达式;

    • 在 condition(条件) 为 true 时执行循环体语句。

    Comment utiliser le script Lua dans lécosystème Java/Redis

    3)break提前退出循环

    和Java中的break一个作用,用于退出当前循环或语句;

    7、函数

    在Lua中,函数是对语句和表达式进行抽象的主要方法。类似于Java中的方法。

    Lua 函数主要有两种用途:

    • 完成指定的任务,这种情况下函数作为调用语句使用;

    • 计算并返回值,这种情况下函数作为赋值语句的表达式使用;

    函数的编写方式如下:

    --[[ 函数返回两个值的最大值 --]]
    function max(num1, num2)
       if (num1 > num2) then
          result = num1;
       else
          result = num2;
       end
       return result; 
    end
    -- 调用函数
    print("两值比较最大值为 ",max(10,4))
    print("两值比较最大值为 ",max(5,6))

    Comment utiliser le script Lua dans lécosystème Java/Redis

    三、Java中执行Lua脚本

    Java中执行Lua脚本有两种方式:字符串的方式、文件的方式;

    Java中想要执行LUA脚本,首先需要在pom中引入相关依赖:

    <dependency>
        <groupId>org.luaj</groupId>
        <artifactId>luaj-jse</artifactId>
        <version>3.0.1</version>
    </dependency>

    1、字符串方式

    对于简单的lua脚本,可以直接用java字符串写;

    package com.saint.base.lua;
    
    import org.luaj.vm2.Globals;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    public class LuaString {
        public static void main(String[] args) {
            String luaStr = "print &#39;Saint is best man&#39;";
            Globals globals = JsePlatform.standardGlobals();
            LuaValue luaValue = globals.load(luaStr);
            luaValue.call();
        }
    }

    控制台输出:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    2、文件方式

    对于一些比较常用的、复杂的脚本可以选择存放在文件中,在Java中再调用lua文件;

    package com.saint.base.lua;
    
    import org.luaj.vm2.Globals;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    import java.io.FileNotFoundException;
    
    public class LuaFile {
        public static void main(String[] args) throws FileNotFoundException {
            // lua脚本的文件路径
            String luaPath = "/xxxx/javaTest.lua";
            Globals globals = JsePlatform.standardGlobals();
            //加载脚本文件login.lua,并编译
            globals.loadfile(luaPath).call();
            LuaValue func1 = globals.get(LuaValue.valueOf("print1"));
            func1.call();
    
            LuaValue func2 = globals.get(LuaValue.valueOf("print2"));
            String luaResp = func2.call(LuaValue.valueOf("saint-input-param")).toString();
            System.out.println("lua file return is : " + luaResp);
        }
    }

    lua脚本文件:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    控制台输出:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    3、Luaj概述

    Luaj在包装执行具体的Lua代码时, 有三种不同的模式;

    • 纯脚本解析执行(不选用任何Compiler)

    • To Lua字节码(LuaC, lua-to-lua-bytecode compiler)(默认选用)

    • To Java字节码(LuaJC, lua-to-java-bytecode compiler)

    Luaj中的Globals对象不是线程安全的, 因此最佳实践是每个线程一个Globals对象。

    事实上, 可以采用ThreadLocal的方式来存储该对象。

    2)性能问题

    Lua脚本在JAVA中运行,相比于直接运行Java代码会慢很多,大约1000倍。

    四、Redis + Lua(EVAL命令)

    在使用Redisson、Jedis+Lua时,我们可以通过redis客户端集成的、手写的LUA脚本来保证一系列命令在Redis中可以"原子执行"。

    在redis执行lua脚本时,相当于一个redis级别的锁,不能执行其他操作,类似于原子操作,这也是redisson实现的一个关键点。

    比如Redisson中的lua脚本:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    Redisson如何实现分布式锁,可以看文章:https://www.yisu.com/article/277312.htm

    lua脚本中有如下几个概念:

    • redis.call():执行redis命令。

    • KEYS[n]:指脚本中第n个参数,比如KEYS[1]指脚本中的第一个参数。

    • ARGV[n]:指脚本中第n个参数的值,比如ARGV[1]指脚本中的第一个参数的值。

    • 返回值中nil与false同一个意思。

    1、EVAL命令

    redis2.6.0版本起 采用内置的Lua解释器 通过EVAL命令去执行脚本;

    redis中的EVAL命令可以用于执行一段lua代码。命令格式如下:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    • 第一个参数script:表示lua脚本的内容;

    • 第二参数numkeys:表示有多少个键值对。

    • 其余参数:先把numkeys个key列出来,再把numkeys个arg列出来。

    Lua脚本中可以使用2个函数调用redis命令;

    • redis.call()

    • redis.pcall()

    redis.call()与redis.pcall()相似,二者唯一不同之处:

    • 如果执行的redis命令执行失败,redis.call()将产生一个Lua error,从而迫使EVAL命令返回一个错误给命令的调用者;

    • 然而redis.pcall()将会捕捉这个错误,并返回代表这个错误的Lua表。

    有那么一段逻辑;

    • 如果Redis某个key的整数值 和 某个value相等,则将key对应的整数值 + 1000;否则将key的值设置为9999;

    lua脚本执行命令如下:

    EVAL "if redis.call(&#39;get&#39;, KEYS[1]) == ARGV[1] then return redis.call(&#39;INCRBY&#39;, KEYS[1], 1000); else redis.call(&#39;set&#39;, KEYS[1], 9999); return nil; end;" 1 test 100

    根据test值的不同,不同的执行结果如下:

    Comment utiliser le script Lua dans lécosystème Java/Redis

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer