redisson对单个json进行操作 - lua脚本

    /**
     * @param key 数值长度只能是 1 (操作string类型) 或者 2 (操作hash类型) 注意如果redis是分布式的,主key必须是第一个
     * @param field 需要操作的 json field
     * @param val 任意字符
     * @param limit 原来的值: 1 数字(limit是数字限制最大值, 否不限制);(默认限制:结果 >= 0 或者 结果 > 上一个值)
     *              2 字符(limit是上一个值才成功, limit是空 上一个值必须是nil, limit == val 不限制)
     * @return errorField 对应的字段不为 null (正确: null, 错误: not null)
     */
    @Override
    public String mUpdateJson(List<String> key, List<String> field, List<Object> val, Map<Integer, String> limit, String errorField) {
        if(key == null || field == null || val == null || limit == null || errorField == null || key.contains(errorField)) {
            throw new RuntimeException("mUpdateJson param error, has null, key: " + key + " field: " + field  +
                    " val:" + val + " limit: " + limit + " errorKey: " + errorField);
        }
        long len = key.stream().filter(Objects::nonNull).count();
        if(len != 1 && len != 2) {
            throw new RuntimeException("mUpdateJson key param error, key array size just 1 or 2.");
        }
        //主key必须是第一个
        String mk = key.get(0);
        List<Object> keyList = key.stream().filter(Objects::nonNull).map(a -> {
            if(!a.equals(mk)) return "{" + mk + "}" + a; else return a;
        }).collect(Collectors.toList());
        keyList.add("{" + mk + "}" + errorField);

        field = field.stream().filter(Objects::nonNull).collect(Collectors.toList());
        if(field.size() > 100) {
            throw new RuntimeException("mUpdateJson operator field length not > 100!");
        }

        val = val.stream().filter(Objects::nonNull).collect(Collectors.toList());
        if(field.size() != val.size()) {
            throw new RuntimeException("mUpdateJson param size error, fieldSize: " + field.size()  + " numSize:"
                    + val.size());
        }
        String splitFunction = "local function getRealKey(str)\n" +
                "local i = string.find(str, '}'); \n" +
                "return string.sub(str, i + 1);\n" +
                "end \n";
        String prefix = len == 1 ? "local t = redis.call('get', KEYS[1]); " :
                " local tf = getRealKey(KEYS[2]); local t = redis.call('hget', KEYS[1], tf); ";
        String middle = " local tf2 = getRealKey(KEYS[" + (len + 1) + "]); j[tf2] = 1; ";
        String suffix = len == 1 ? "redis.call('set', KEYS[1], er); " :
                " local tf3 = getRealKey(KEYS[2]); redis.call('hset', KEYS[1], tf3, er); ";
        String script = splitFunction + prefix +
                "local j; local err = false;\n" +
                "if t then j = cjson.decode(t); else j = cjson.decode(\"{}\"); end;\n" +
                "local n;\n" +
                "for i = 1, #ARGV, 3 do \n" +
                "local v = tonumber(ARGV[i + 1]);\n" +
                "if v then \n" +
                "if j[ARGV[i]] then n = tonumber(j[ARGV[i]]); else n = 0 end;\n" +
                "local r = n + v\n" +
                "local limit = tonumber(ARGV[i + 2]);\n" +
                "if (r >= 0 or r > n) and (not limit or r <= limit) then j[ARGV[i]] = r;\n" +
                "else j[ARGV[i]] = r; err = true; " + middle + " end;\n" +
                "else " +
                "if (ARGV[i + 2] == '' and not j[ARGV[i]]) or ARGV[i + 2] == ARGV[i + 1] or ARGV[i + 2] == j[ARGV[i]] " +
                "then j[ARGV[i]] = ARGV[i + 1]; " +
                "else if j[ARGV[i]] == ARGV[i + 1] then j[ARGV[i]] = ARGV[i + 2] end; err = true; " + middle + " end; end;\n" +
                "end; \n" +
                "local er = cjson.encode(j);\n" +
                "if err then return er;\n" +
                "else " + suffix + " return er end;";
        //System.out.println(script.replaceAll("\n", " "));
        RScript rscript = redissonClient.getScript();
        int size = field.size();
        Object[] param = new Object[size * 3];
        for(int i = 0;i < size;i++) {
            param[3 * i] = field.get(i);
            param[3 * i + 1] = val.get(i);
            param[3 * i + 2] = limit.get(i) == null ? "" : limit.get(i);
        }

        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE, keyList, param);
    }

 

posted @ 2023-06-30 14:31  数学与IT  阅读(43)  评论(0编辑  收藏  举报