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); }