zoukankan      html  css  js  c++  java
  • 用jedis执行lua脚本

    1.Redis 脚本

    Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 EVAL。

    下表列出了 redis 脚本常用命令:

    序号命令及描述
    1 EVAL script numkeys key [key ...] arg [arg ...]
    执行 Lua 脚本。
    2 EVALSHA sha1 numkeys key [key ...] arg [arg ...]
    执行 Lua 脚本。
    3 SCRIPT EXISTS script [script ...]
    查看指定的脚本是否已经被保存在缓存当中。
    4 SCRIPT FLUSH
    从脚本缓存中移除所有脚本。
    5 SCRIPT KILL
    杀死当前正在运行的 Lua 脚本。
    6 SCRIPT LOAD script
    将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

    2.lua 文件编写和执行

    ip_limit.lua :

    -- IP限流,对某个IP频率进行限制 ,1分钟访问10次
    local num=redis.call('incr',KEYS[1])
    if tonumber(num)==1 then
        redis.call('expire',KEYS[1],ARGV[1])
        return 1
    elseif tonumber(num)>tonumber(ARGV[2]) then
        return 0
    else 
        return 1
    end

    执行 ip_limit.lua 脚本:

    ./redis-cli --eval  "ip_limit.lua"  app:ip:limit:192.168.1.15 , 6000 10
    (integer) 1

    注意
      1) app:ip:limit:192.168.1.15 是key值 ,后面是参数值,中间要加上一个空格 和 一个逗号,再加上一个 空格 。即:./redis-cli –eval [lua脚本] [key…]空格,空格[args…]
      2) 多个参数之间用一个 空格 分割 。

    3.evalsha 的基本使用

    每次使用 eval 执行很长的脚本其实没什么必要, redis可以将脚本缓存起来,生成一个脚本的 SHA1 ,标记这个这个脚本,然后 使用时传 SHA1 和key value 的值即可。

    92:0>script load "return redis.call('set',KEYS[1],ARGV[1])"    # 这段脚本 生成了SHA1 值,来标记其唯一性
    "c686f316aaf1eb01d5a4de1b0b63cd233010e63d"                                     
    92:0>evalsha c686f316aaf1eb01d5a4de1b0b63cd233010e63d 1 AA BB   # 使用 evalsha 命令 和 SHA1 值来执行脚本
    "OK"
    92:0>get AA          # 验证数据存储是否成功
    "BB"

    4.redis 和 java 整合

    jedis.scriptLoad方法将script 脚本添加到脚本缓存中,如果脚本没有加载过,那么进行加载,这样就会返回一个sha1编码。
    jedis.evalsha() 根据sha1编码 和 key value值执行脚本,返回结果。

    依赖:

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.6.0</version>
    </dependency>

    代码如下,

    Jedis连接池:

    public class JedisPoolUtils {
    
        private static JedisPool jedisPool;
    
        public static JedisPool getInstance() {
            if (jedisPool == null) {
                synchronized (JedisPoolUtils.class) {
                    if (jedisPool == null) {
                        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                        jedisPoolConfig.setMaxTotal(20);
                        jedisPoolConfig.setMaxIdle(10);
                        jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379, 4000, "123456");
                    }
                }
            }
            return jedisPool;
        }
    }

    测试实现类:

    public class LuaDemo{
    
        @Test
        public void  testScriptLoad() {
            JedisPool jedisPool = JedisPoolUtils.getInstance();
            Jedis jedis = jedisPool.getResource();
            System.out.println(jedis);
             String lua = "local num = redis.call('incr', KEYS[1])
    " +
                     "if tonumber(num) == 1 then
    " +
                     "	redis.call('expire', KEYS[1], ARGV[1])
    " +
                     "	return 1
    " +
                     "elseif tonumber(num) > tonumber(ARGV[2]) then
    " +
                     "	return 0
    " +
                     "else 
    " +
                     "	return 1
    " +
                     "end
    ";
            String scriptLoad=jedis.scriptLoad(lua);
            System.out.println(scriptLoad);
        }    
        
        @Test
        public  void testEvalsha() {
            JedisPool jedisPool = JedisPoolUtils.getInstance();
            Jedis jedis = jedisPool.getResource();
            try {
               String scriptLoad ="5ae1f63a19ef16ea0d8c0268d01c5fa01312b7e6";  //来自上面的 testScriptLoad()的值
                Object result = jedis.evalsha(scriptLoad , Arrays.asList("localhost"), Arrays.asList("10000", "2"));
                System.out.println("aaa:"+result);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(jedis != null){
                    try {
                        jedis.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
        
        @Test
        public void script() throws InterruptedException {
        
            JedisPool jedisPool = JedisPoolUtils.getInstance();
            Jedis jedis = jedisPool.getResource();
            List<String> keys = new ArrayList<>();
            List<String> vals = new ArrayList<>();
            
            // 测试1、 基本测试
            Object eval = jedis.eval("return 1", keys, vals);
            System.out.println(eval);
            
            // 测试2、 eval  里面也可以是一个文件
            keys.add("kk");
            Object eval2 = jedis.eval("local tab={}  for i=1,#KEYS do  tab[i] = redis.call('get',KEYS[i]) end return tab",
                    keys, vals);
            System.out.println(eval2);
            
            // 测试3、 scriptLoad 
            //好处:这样可以缓存到服务器,不用每次把lua脚本的内容传过去
            String lua = "local tab={}  for i=1,#KEYS do  tab[i] = redis.call('get',KEYS[i]) end return tab";
            String scriptLoad = jedis.scriptLoad(lua);
            System.out.println(scriptLoad);
            Object evalsha = jedis.evalsha(scriptLoad, keys, vals);
            System.out.println(evalsha);
       }       
    }

    参考:

    https://zixuephp.net/manual-redis-2328.html

    https://blog.csdn.net/xiaojin21cen/article/details/88621540

    https://blog.csdn.net/weixin_38070406/article/details/78246786

  • 相关阅读:
    swift4.2
    swift4.2 打印devicetoken
    swift4.2
    (二十三)Dbutils 工具介绍
    (二十二)自定义简化版JDBC(Dbutils框架的设计思想)
    (二十一)配置三种开源数据库连接池
    (二十)自定义数据库连接池
    (十九)事务
    (十八)JDBC获取存储过程和主键
    (十七)使用JDBC进行批处理
  • 原文地址:https://www.cnblogs.com/sfnz/p/15060642.html
Copyright © 2011-2022 走看看