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脚本零到多个键,KEYS[index],注意索引从1开始。

ARGV数组

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

redis.call()

用来调用redis命令。

Hello Lua脚本案例

脚本编辑

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

传入的redis key为数组,使用KEYS[index]传参,

传入的redis value为数组,使用ARGV[index]传值。

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

相关推荐
Kagol9 小时前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
hzulwy9 小时前
Redis常用的数据结构及其使用场景
数据库·redis
ashane131411 小时前
Redis 哨兵集群(Sentinel)与 Cluster 集群对比
redis
Y第五个季节12 小时前
Redis - HyperLogLog
数据库·redis·缓存
Justice link12 小时前
企业级NoSql数据库Redis集群
数据库·redis·缓存
monstercl15 小时前
Lua中基础函数使用详解
lua·脚本语言
爱的叹息15 小时前
Spring Boot 集成Redis 的Lua脚本详解
spring boot·redis·lua
morris1311 天前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
爱的叹息1 天前
spring boot集成reids的 RedisTemplate 序列化器详细对比(官方及非官方)
redis
weitinting1 天前
Ali linux 通过yum安装redis
linux·redis