redis的搭建及应用(六)-redis应用LUA脚本

edis的lua脚本

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于 1993 年开发的,该小组成员有:Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo

lua脚本设计目的

其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

lua脚本在redis中的应用

从 Redis 2.6.0 版本开始起;可通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行执行。

在redis中使用lua脚本的好处:

  • 支持原子性操作 - Redis会将整个脚本作为一个整体执行(原子性),中间不会被其他请求插入。因此在脚本运行过程中无需担心会出现竞态条件,无需使用事务。

  • 降低网络开销 - 将多个请求通过脚本的形式一次发送到服务器,减少了网络的时延。

  • 脚本复用 - 客户端发送的脚本可支持永久存在redis中,这样其他客户端可以复用这一脚本,而不需要使用代码完成相同的逻辑。

lua基本语法

lua变量
局部变量

local a = 5

全局变量

不需要local关键字。

lua 复制代码
a = 12                  -- 全局变量
local b=3
条件语句

if 条件

:

then

end

if 条件

then

else

end

KEYS数组

传递给Lua脚本零到多个键,KEYSindex,注意索引从1开始。

ARGV数组

是传递给脚本的零到多个附加参数, ARGVindex,注意索引从1开始。

redis.call()

用来调用redis命令。

Hello Lua脚本案例

脚本编辑

在resource路径下创建lua/hello.lua文件

传入的redis key为数组,使用KEYSindex传参,

传入的redis value为数组,使用ARGVindex传值。

lua 复制代码
-- key
local k1 = KEYS[1]
local k2 = KEYS[2]
local k3 = KEYS[3]
-- value
local v1 = ARGV[1]
redis.call('set',k1,v1)
redis.call('set',k2,v1)
redis.call('set',k3,v1)
return "OK"
springboot配置

定义一个读取lua脚本的配置类。

java 复制代码
@Bean
public DefaultRedisScript<String> defaultRedisScript(){
    DefaultRedisScript<String> defaultRedisScript = new DefaultRedisScript<>();
    defaultRedisScript.setResultType(String.class);
    defaultRedisScript.setLocation(new ClassPathResource("lua/hello.lua"));
    return defaultRedisScript;
}
单元测试
java 复制代码
@Test
public void luaTest(){}
List<String> keys = new ArrayList<>();
        keys.add("money01");
        keys.add("money02");
        keys.add("money03");
        String val1 = "100";
        String val2 = "150";
        String val3 = "200";
        String execute = stringRedisTemplate.opsForValue()
                .getOperations()
                .execute(defaultRedisScript,
                        keys,
                        val1,val2,val3);
        System.out.println("lua调用: "+ execute);
    }
}

springboot中Lua脚本的创建流程

定义脚本文件方式
创建lua文件

resources/lua/xxx.lua

编辑lua脚本
  • local 本地变量 类似于js var

  • KEYS数组, 从外界传入的key,下标 从1 开始

  • ARGV 数组, 外界命令中传输的值

  • 条件 :

    lua 复制代码
    if   条件   then
     ...
    else
     ....
    end
  • tonumber():将字符串转换为数值

  • return

定义script对象读取lua脚本
java 复制代码
@Bean
public DefaultRedisScript<String> defaultRedisScript(){
    DefaultRedisScript<String> defaultRedisScript = new DefaultRedisScript<>();
    defaultRedisScript.setResultType(String.class);
    defaultRedisScript.setLocation(new ClassPathResource("lua/hello.lua"));
    return defaultRedisScript;
}
执行脚本
java 复制代码
stringRedisTemplate.opForValue()
                   .getOpertation()
                   .execute(
                      defaultRedisScript,
                      keys             //ArrayList
                      val1,val2...      //值
                   );
代码方式实现

将脚本文件的内容转换为字符串,如果lua脚本比较小,在不同程序中lua内容比较灵活,聚合性比较高。可以采用此种方式。

java 复制代码
String script = "local k1 = KEYS[1]\n" +
            "local k2 = KEYS[2]\n" +
            "local k3 = KEYS[3]\n" +
            "local v1 = ARGV[1]\n" +
            "local v2 = ARGV[2]\n" +
            "local v3 = ARGV[3]\n" +
            "\n" +
            "redis.call('set',k1,v1)\n" +
            "redis.call('set',k2,v2)\n" +
            "redis.call('set',k3,v3)\n" +
            "\n" +
            "return \"OK\"";
String execute = stringRedisTemplate.opsForValue()
        .getOperations()
        .execute(
               new DefaultRedisScript<>(script,String.class),
                new ArrayList<String>(){{
                    add("m1");
                    add("m2");
                    add("m3");
                }},
                10, 20, 30);
System.out.println("lua调用: "+ execute);
    String execute = stringRedisTemplate.opsForValue()
            .getOperations()
            .execute(
                    new DefaultRedisScript<>("local k1 = KEYS[1] local k2 = KEYS[2] local k3 = KEYS[3] local v1 = ARGV[1] local v2 = ARGV[2] local v3 = ARGV[3] redis.call('set',k1,v1) redis.call('set',k2,v2) redis.call('set',k3,v3) return \"OK\"", String.class),
                    new ArrayList<String>() {{
                        add("m1");
                        add("m2");
                        add("m3");
                    }},
                    "100", "20", "30");
    System.out.println("lua调用: " + execute);

lua脚本创建布隆过滤器

shell 复制代码
127.0.0.1:6379> BF.ADD newFilter bmFilter
(integer) 1
127.0.0.1:6379> 

编写lua脚本

在resource下创建lua脚本

lua 复制代码
local key = KEYS[1]
local val = ARGV[1]

local retVal = tonumber(redis.call('BF.ADD',key,val))

if retVal==1 then
    return 1
else
    return 0
end

测试

java 复制代码
@Test
public void testLua() {
    List<String> keys = new ArrayList<>();
    keys.add("bmFilter");

    Long t = (Long) stringRedisTemplate.opsForValue().getOperations()
            .execute(redisScript, keys, "admin888");
    System.out.println("--->"+t);

}

代码中加入脚本

java 复制代码
List<String> keys = new ArrayList<>();
keys.add("bmFilter");
String script ="return redis.call('BF.EXISTS',KEYS[1],ARGV[1])";
Long s = stringRedisTemplate.opsForValue().getOperations()
        .execute(new DefaultRedisScript<Long>(script,Long.class), keys,username);

log.debug("s--->", s);

下一章我们研究-redis的限流插件redis-cell

相关推荐
IT大白鼠2 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz2 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
lbb 小魔仙2 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
夕除2 天前
redis--018
redis
两锭子2 天前
Redis基础
redis
烟沙九洲2 天前
Redis 缓存穿透、缓存击穿、缓存雪崩
数据库·redis
字节探索2 天前
Redis 只会当缓存用?这 10 大实战场景,让你的系统快到飞起
redis·后端
于樱花森上飞舞2 天前
【Redis】哨兵详解
java·开发语言·数据库·redis
Rain的Java大神之路2 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog2 天前
Java 接入Redis: 通用命令与键管理
java·服务器·redis