Redis中使用Lua语言详谈

在Redis的2.6以上版本中,除了可以使用命令外,还可以使用Lua语言操作Redis。
Redis支持两种方式运行脚本,一种是直接输入一些Lua语言的程序代码;另外一种使将Lua语言编写成文件。

初步认识Lua程序代码

他的命令格式是:

eval lua-script key-num [key1,key2,key3 ...] [value1 value2 value3 ...]

其中:

  • eval代表执行Lua语言的命令。
  • lua-script代表Lua语言脚本。
  • key-num整数代表参数中有多少个key,需要注意的是Redis中key是从1开始的,如果没有key的参数,那么写0.
  • [key1,key2,key3 …]:key作为参数传递给Lua语言,也可以不填,但是需要和key-num的个数对应起来。
  • [value1 value2 value3 …]:作为参数传递给Lua语言,它们也是可填可不填的。

这里我们看两个Lua脚本:

eval "return 'Hello World!'" 0

这个脚本只是返回一个字符串,并不需要任何参数,所以key-num填写了0,代表着没有任何key参数,执行结果就是返回 Hello World!。

eval "redis.call('set',KEYS[1],ARGV[1]" 1 lua-key lua-value

设置一个键值对,可以在Lua语言中采用redis.call(command,key[param1,param2…])进行操作,其中:

  • command是命令,包括set,get,del等。
  • key是被操作的键。
  • param1,param2…代表给key的参数。

有时候可能需要多次执行同样一段脚本,这个时候可以使用Redis缓存脚本的功能,在Redis中脚本会通过SHA-1签名算法加密脚本,然后返回一个标识字符串,可以通过这个字符串执行加密后的脚本。
首先使用命令:

script load script

这个脚本的返回值是一个SHA-1签名过后的标识字符串,我们把它记为shastring。通过shastring可以使用命令执行签名后的脚本,命令的格式是:

evalsha shastring keynum [key1 key2 key3 ...] [param1 param2 param3 ...]

下面我们在Spring中演示这个过程。

这里我们先定义一个可序列化的对象Role,因为要序列化所以需要实现Serializable接口,代码如下:

package com.ssm.lua.pojo;

import java.io.Serializable;

public class Role implements Serializable {
    private static final long serialVersionUID=7247714666080613254L;
    private Long id;
    private String roleName;
    private String note;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="50" />
        <property name="maxTotal" value="100" />
        <property name="maxWaitMillis" value="20000" />
    </bean>

    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />

    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="localhost" />
        <property name="port" value="6379" />
        <property name="password" value="123456" />
        <property name="poolConfig" ref="poolConfig" />
    </bean>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="defaultSerializer" ref="stringRedisSerializer" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer" />
    </bean>
</beans>

这个时候就可以通过Spring提供的DefaultRedisScript对象执行Lua脚本来操作对象,代码如下:

package com.ssm.lua.test;

import com.ssm.lua.pojo.Role;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import java.util.ArrayList;
import java.util.List;

public class testLua {
    public static void main(String[] args){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("redisSpring-cfg.xml");
        RedisTemplate redisTemplate=applicationContext.getBean(RedisTemplate.class);
        //定义默认脚本封装类
        DefaultRedisScript<Role> redisScript=new DefaultRedisScript<>();
        //设置脚本
        redisScript.setScriptText("redis.call('set',KEYS[1],ARGV[1]) return redis.call('get',KEYS[1])");
        //定义操作的key列表
        List<String> keyList=new ArrayList<>();
        keyList.add("role1");
        //需要序列化保存和读取的对象
        Role role=new Role();
        role.setId(1L);
        role.setRoleName("role_name_1");
        role.setNote("role_note_1");
        //获取标识字符串
        String shastring=redisScript.getSha1();
        System.out.println(shastring);
        //设置返回结果的类型,如果没有这句话,结果返回为空。
        redisScript.setResultType(Role.class);
        //定义序列化器
        JdkSerializationRedisSerializer serializer=new JdkSerializationRedisSerializer();
        //执行脚本
        //第一个是RedisScript接口对象,第二个是参数序列化器
        //第三个是结果序列化器,第四个是Redis的key列表,最后是参数列表
        Role obj=(Role)redisTemplate.execute(redisScript,serializer,serializer,keyList,role);
        //打印结果
        System.out.println(obj);
    }
}

执行Lua文件

在上面我们把Lua变成一个字符串传递给Redis执行,而有些时候要直接执行Lua文件,尤其是当Lua脚本存在很多逻辑的时候,就很有必要单独编写一个独立的Lua文件:

redis.call('set',KEYS[1],ARGV[1])
redis.call('set',KEYS[2],ARGV[2])
local n1=tonumber(redis.call('get',KEYS[1]))
local n2=tonumber(redis.call('get',KEYS[2]))
if n1>n2 then
	return 1
end
if n1==n2 then
	return 0
end
if n1<n2 then
	return 2
end

这是一个可以输入两个键和两个数字(记为n1和n2)的脚本,其意义就是先按键保存两个数字,然后去比较这两个数字的大小。且把它以文件名test.lua保存起来。这个时候可以对其进行测试。

redis-cli --eval test.lua key1 key2 , 2 4

这里需要非常注意命令,执行的命令键和参数是要使用逗号隔开的,而键之间用空格分开。而上面的逗号前后的空格是不能省略的,这是要非常注意的地方。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值