Springboot redis使用lua和pipeline


LUA

Lua是作為嵌入式腳本的最佳選擇,速度非常快

在redis命令行中,可以直接調用lua腳本,比如

127.0.0.1:6380> eval "local result={}  for loop=1, #(KEYS) do result[loop]=redis.call('hget',KEYS[loop], ARGV[1]) end return result" 3 xiaoa xiaob xiaoc count

1) "2"
2) "5"
3) "1"
127.0.0.1:6380>

 

使用SpringBoot調用lua腳本,存在兩種方式

一、直接在代碼中通過字符串調用

        StringBuilder lua = new StringBuilder();
        lua.append("local result={} ");
        lua.append("for loop=1, #(KEYS) ");
        lua.append("do result[loop]=redis.call('hget',KEYS[loop], ARGV[1]) ");
        lua.append("end ");
        lua.append("return result");

        RedisScript<List> script = RedisScript.of(lua.toString(), List.class);

        List<String> keys = new ArrayList<String>();
        keys.add("xiaoa");
        keys.add("xiaob");
        keys.add("xiaoc");

        List<Object> args = new ArrayList<>();
        args.add("count");

        List<String> result = redisTemplate.execute(script, keys, args.toArray());

        logger.info("luaTest: {}", result);

二、通過lua腳本文件調用

1、腳本文件,count_qry.lua

local result={}
  for loop = 1,#(KEYS)
      do result[loop]= redis.call('hget',KEYS[loop], ARGV[1])
  end
return result

 

        // src/main/resources下
        ClassPathResource resource = new ClassPathResource("lua/count_qry.lua");
        RedisScript<List> script = RedisScript.of(resource, List.class);

        List<String> keys = new ArrayList<String>();
        keys.add("xiaoa");
        keys.add("xiaob");
        keys.add("xiaoc");

        List<Object> args = new ArrayList<>();
        args.add("count");

        List<String> result = redisTemplate.execute(script, keys, args.toArray());

        logger.info("luaFileTest: {}", result);

使用springboot pipeline也能實現上述的功能

        List<Object> result = redisTemplate.executePipelined(new RedisCallback() {

            @Override
            public List<String> doInRedis(RedisConnection connection) throws DataAccessException {
                List<String> keys = new ArrayList<String>();
                keys.add("xiaoa");
                keys.add("xiaob");
                keys.add("xiaoc");

                for (int i = 0; i < keys.size(); i++) {
                    connection.hGet(keys.get(i).getBytes(), "count".getBytes());
                }
                // 必須返回null,否則將出現異常
                return null;
            }
        });

        logger.info("result: {}", result);

 

使用lua腳本和pipeline都可以實現簡單的原子性,但lua腳本比pipelin更靈活,實現功能更多,比如有個隊列,存放的數據不能超過N個,超過的將不會被存儲,這種實現方式很多,其中一種方式比如在插入隊列數據之前,先查詢下數據個數,大於等於N個,則不添加,這個邏輯用pipeline不能夠實現,但可以用lua實現,假設N=3

local len=redis.call('llen',KEYS[1])
if len >= 3
    then return false
else
    redis.call('lpush',KEYS[1],ARGV[1])
    return true
end

 

        // src/main/resources下
        ClassPathResource resource = new ClassPathResource("lua/queue.lua");
        RedisScript<Boolean> script = RedisScript.of(resource, Boolean.class);

        List<String> keys = new ArrayList<String>();
        keys.add("testqueue");
        List<Object> args = new ArrayList<>();
        args.add("val");

        for (int i = 0; i < 4; i++) {
            boolean result = redisTemplate.execute(script, keys, args.toArray());
            logger.info("add val to queue result: {}", result);
        }

結果,前三個數據成功插入,第四個數據被拒絕

2021-12-24 15:29:36.961  INFO 34276 --- [           main] com.demo.redistest.RedisLuaTest          : add val to queue result: true
2021-12-24 15:29:36.964  INFO 34276 --- [           main] com.demo.redistest.RedisLuaTest          : add val to queue result: true
2021-12-24 15:29:36.966  INFO 34276 --- [           main] com.demo.redistest.RedisLuaTest          : add val to queue result: true
2021-12-24 15:29:36.968  INFO 34276 --- [           main] com.demo.redistest.RedisLuaTest          : add val to queue result: false

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM