redisson 工具类

发布时间 2023-09-19 17:29:40作者: 数学与IT
import com.alibaba.fastjson.JSON;
import com.juxiao.xchat.dao.room.dto.CallStatus;
import com.juxiao.xchat.manager.cache.redis.RedissonManager;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.redisson.client.protocol.ScoredEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RedissonManagerImpl implements RedissonManager {
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public RLock lock(String key, int waitTime, int lockTimeout) {
        RLock rLock = redissonClient.getLock(key);
        try {
            if (rLock.tryLock(waitTime, lockTimeout, TimeUnit.SECONDS)) {
                return rLock;
            }
        } catch (InterruptedException e) {
            log.error("[ Redisson ] tryLock err:", e);
        }
        return null;
    }

    @Override
    public RLock fairLock(String key, int waitTime, int lockTimeout) {
        RLock rLock = redissonClient.getFairLock(key);
        try {
            if (rLock.tryLock(waitTime, lockTimeout, TimeUnit.SECONDS)) {
                return rLock;
            }
        } catch (InterruptedException e) {
            log.error("[ Redisson ] tryLock err:", e);
        }
        return null;
    }

    @Override
    public long del(String... key) {
        RKeys rKeys = redissonClient.getKeys();
        return rKeys.delete(key);
    }

    @Override
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        RKeys rKeys = redissonClient.getKeys();
        return rKeys.expire(key, time, timeUnit);
    }

    @Override
    public Iterable<String> keys(String key) {
        RKeys rKeys = redissonClient.getKeys();
        return rKeys.getKeysByPattern(key);
    }

    @Override
    public boolean exists(String key) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.isExists();
    }

    @Override
    public Long getExpire(String key) {
        RKeys rKeys = redissonClient.getKeys();
        return rKeys.remainTimeToLive(key);
    }

    @Override
    public long ttl(String key) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.remainTimeToLive();
    }

    @Override
    public String get(String key) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.get();
    }

    @Override
    public Map<String, String> mGet(String... key) {
        RBuckets rBuckets = redissonClient.getBuckets();
        return rBuckets.get(key);
    }

    @Override
    public void set(String key, String value) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        rBucket.set(value);
    }

    @Override
    public String getAndSet(String key, String value) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.getAndSet(value);
    }

    @Override
    public String getAndDelete(String key) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.getAndDelete();
    }

    @Override
    public void set(String key, String value, int time, TimeUnit timeUnit) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        rBucket.set(value, time, timeUnit);
    }

    @Override
    public void set(String key, String value, long time, TimeUnit timeUnit) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        rBucket.set(value, time, timeUnit);
    }

    @Override
    public boolean setnx(String key, String value) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.trySet(value);
    }

    @Override
    public boolean setnx(String key, String value, long time, TimeUnit timeUnit) {
        RBucket<String> rBucket = redissonClient.getBucket(key);
        return rBucket.trySet(value, time, timeUnit);
    }

    @Override
    public boolean msetnx(Map<String, String> map) {
        RBuckets rBuckets = redissonClient.getBuckets();
        return rBuckets.trySet(map);
    }

    @Override
    public boolean msetnx(String key, String otherKey, String value, String otherValue) {
        Map<String, String> map = new HashMap<>();
        map.put(key, value);
        map.put(otherKey, otherValue);
        return msetnx(map);
    }

    private final static String SCRIPT_1 =
            "local v1 = redis.call('SETNX',KEYS[1],ARGV[1]); " +
                    "local v2 = redis.call('SETNX',KEYS[2],ARGV[2]); " +
                    "return v1 + v2; ";

    @Override
    public Long setnx(String key, String otherKey, String value, String otherValue) {
        RScript rScript = redissonClient.getScript();
        List<Object> list = new ArrayList<>();
        list.add(key);
        list.add(otherKey);
        List<Object> params = new ArrayList(2);
        params.add(value);
        params.add(otherValue);
        return rScript.eval(RScript.Mode.READ_WRITE, SCRIPT_1, RScript.ReturnType.INTEGER, list, params.toArray());
    }

    private final static String SCRIPT_2 = "local val = redis.call('MSETNX',KEYS[1],ARGV[1],KEYS[2],ARGV[2]) " +
            "if val == 0 then " +
            "  return 0  " +
            "else " +
            "  redis.call('Expire', KEYS[1],ARGV[3]) " +
            "  redis.call('Expire', KEYS[2],ARGV[3]) " +
            "  return 1 " +
            "end";

    @Override
    public Long msetnx(String key, String otherKey, String value, String otherValue, String timeoutSeconds) {
        RScript rScript = redissonClient.getScript();
        List<Object> list = new ArrayList<>();
        list.add(key);
        list.add(otherKey);
        List<Object> params = new ArrayList(2);
        params.add(value);
        params.add(otherValue);
        params.add(timeoutSeconds);
        return rScript.eval(RScript.Mode.READ_WRITE, SCRIPT_2, RScript.ReturnType.INTEGER, list, params.toArray());
    }

    @Override
    public Long increment(String key, Long value) {
        RAtomicLong rAtomicLong = redissonClient.getAtomicLong(key);
        return rAtomicLong.addAndGet(value);
    }

    @Override
    public Double increment(String key, Double value) {
        RAtomicDouble rAtomicDouble = redissonClient.getAtomicDouble(key);
        return rAtomicDouble.addAndGet(value);
    }

    @Override
    public long incrByTime(String key, int timeout) {
        RAtomicLong rAtomicLong = redissonClient.getAtomicLong(key);
        long result = rAtomicLong.addAndGet(1);
        rAtomicLong.expire(timeout, TimeUnit.SECONDS);
        return result;
    }

    @Override
    public String hGet(String key, String field) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.get(field);
    }

    @Override
    public Map<String, String> hMGet(String key, Set<String> field) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.getAll(field);
    }

    @Override
    public Map<String, String> hGetAll(String key) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.readAllMap();
    }

    @Override
    public int hLen(String key) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.size();
    }

    @Override
    public String hSet(String key, String field, String value) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.put(field, value);
    }

    @Override
    public void hSetAll(String key, Map<String, String> value) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        rMap.putAll(value);
    }

    @Override
    public String hSet(String key, String field, String value, int time, TimeUnit timeUnit) {
        RMapCache<String, String> rMapCache = redissonClient.getMapCache(key);
        return rMapCache.put(field, value, time, timeUnit);
    }

    @Override
    public boolean hSetIfAbsent(String key, String field, String value) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.fastPutIfAbsent(field, value);
    }

    @Override
    public Integer hIncrement(String key, String field, Integer value) {
        RMap<String, Integer> rMap = redissonClient.getMap(key);
        return rMap.addAndGet(field, value);
    }

    @Override
    public Long hIncrement(String key, String field, Long value) {
        RMap<String, Long> rMap = redissonClient.getMap(key);
        return rMap.addAndGet(field, value);
    }

    @Override
    public Double hIncrement(String key, String field, Double value) {
        RMap<String, Double> rMap = redissonClient.getMap(key);
        return rMap.addAndGet(field, value);
    }

    @Override
    public String hDel(String key, String field) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.remove(field);
    }

    @Override
    public Long hDelKeys(String key, String[] fields) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.fastRemove(fields);
    }

    @Override
    public Set<String> hKeys(String key) {
        RMap<String, String> rMap = redissonClient.getMap(key);
        return rMap.keySet();
    }

    @Override
    public boolean pushAll(String key, List<String> values) {
        RList<String> rList = redissonClient.getList(key);
        return rList.addAll(values);
    }

    @Override
    public void leftPush(String key, String value) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        rDeque.addFirst(value);
    }

    @Override
    public String leftPop(String key) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.pollFirst();
    }

    @Override
    public List<String> lPop(String key, int size) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.pollFirst(size);
    }

    @Override
    public void rightPush(String key, String value) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        rDeque.addLast(value);
    }

    @Override
    public int rPush(String key, String[] value) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.addFirstIfExists(value);
    }

    @Override
    public String rightPop(String key) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.pollLast();
    }

    @Override
    public boolean lRemove(String key, Integer count, String value) {
        RList<String> rList = redissonClient.getList(key);
        return rList.remove(value, count);
    }

    @Override
    public List<String> lRange(String key, int start, int end) {
        RList<String> rList = redissonClient.getList(key);
        return rList.range(start, end);
    }

    @Override
    public int lSize(String key) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.size();
    }

    @Override
    public List<String> listAll(String key) {
        RDeque<String> rDeque = redissonClient.getDeque(key);
        return rDeque.readAll();
    }

    @Override
    public boolean zAdd(String key, String field, double score) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.add(score, field);
    }

    @Override
    public boolean zAdd(String key, double score, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.add(score, field);
    }

    @Override
    public int zAddAll(String key, Map<String, Double> map) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.addAll(map);
    }

    @Override
    public Double zIncrement(String key, String field, Double score) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.addScore(field, score);
    }

    @Override
    public Double zIncrement(String key, Double score, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.addScore(field, score);
    }

    @Override
    public Double zIncrement(String key, Long score, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.addScore(field, score);
    }

    private final static String ZINCRBY_IF_EXISTS = "local val = redis.call('ZRANK',KEYS[1],ARGV[1]) " +
            "if val == false or val == nil then " +
            "  return nil  " +
            "else " +
            "  return redis.call('ZINCRBY', KEYS[1],ARGV[2],ARGV[1]) " +
            "end";

    @Override
    public String zincrbyIfExists(String key, String member, double increment) {
        RScript rScript = redissonClient.getScript();
        List<Object> list = new ArrayList<>();
        list.add(key);
        List<Object> params = new ArrayList(2);
        params.add(member);
        params.add(increment);
        return rScript.eval(RScript.Mode.READ_WRITE, ZINCRBY_IF_EXISTS, RScript.ReturnType.VALUE, list, params.toArray());
    }

    @Override
    public Integer zRank(String key, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.rank(field);
    }

    @Override
    public Integer reverseZRank(String key, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.revRank(field);
    }

    @Override
    public int zCard(String key) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.size();
    }

    @Override
    public Double zScore(String key, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.getScore(field);
    }

    @Override
    public boolean zRemove(String key, String field) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.remove(field);
    }

    @Override
    public int zRemoveByScore(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.removeRangeByScore(min, true, max, true);
    }

    @Override
    public int removeRange(String key, int start, int end) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.removeRangeByRank(start, end);
    }

    @Override
    public int removeRangeByScore(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.removeRangeByScore(min, true, max, true);
    }

    @Override
    public boolean zRemoveAll(String key, List<String> fieldList) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.removeAll(fieldList);
    }

    @Override
    public Integer getZetSize(String key) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.size();
    }

    @Override
    public long zcount(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.count(min, true, max, true);
    }

    @Override
    public Collection<ScoredEntry<String>> zRange(String key, int start, int end) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.entryRange(start, end);
    }

    @Override
    public Collection<ScoredEntry<String>> reverseZRange(String key, int start, int end) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.entryRangeReversed(start, end);
    }

    @Override
    public Collection<ScoredEntry<String>> zRangeByScore(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.entryRange(min, true, max, true);
    }

    @Override
    public Collection<ScoredEntry<String>> reverseZRangeByScore(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.entryRangeReversed(min, true, max, true);
    }

    @Override
    public Collection<String> zrangeByScore(String key, double min, double max) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.valueRange(min, true, max, true);
    }

    @Override
    public Collection<String> zrevRangeByScore(String key, double max, double min) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.valueRangeReversed(min, true, max, true);
    }

    @Override
    public Collection<String> zrange(String key, int start, int end) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.valueRange(start, end);
    }

    @Override
    public Collection<String> zrevrange(String key, long start, long end) {
        RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet(key);
        return rScoredSortedSet.valueRangeReversed((int) start, (int) end);
    }

    @Override
    public boolean sExists(String key) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.isExists();
    }

    @Override
    public boolean sIsMember(String key, String field) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.contains(field);
    }

    @Override
    public boolean sAdd(String key, String field) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.add(field);
    }

    @Override
    public boolean sAddAll(String key, Collection<String> field) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.addAll(field);
    }

    @Override
    public boolean sRemove(String key, String field) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.remove(field);
    }

    @Override
    public Set<String> sPop(String key, int size) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.removeRandom(size);
    }

    @Override
    public int sCard(String key) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.size();
    }

    @Override
    public Set<String> sMembers(String key) {
        RSet<String> rSet = redissonClient.getSet(key);
        return rSet.readAll();
    }

    @Override
    public long sAddAndCard(String key, String field) {
        String script = "redis.call('sAdd', KEYS[1], ARGV[1]); " +
                "return redis.call('sCard', KEYS[1]); ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.INTEGER,
                Collections.singletonList(key), field);
    }

    @Override
    public boolean hSetIfExist(String key, String field, String value) {
        String script = "local n = redis.call('hGet', KEYS[1], ARGV[1]); " +
                "if n then " +
                "redis.call('hSet', KEYS[1], ARGV[1], ARGV[2]); " +
                "return true;" +
                "else " +
                "return false;" +
                "end; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.BOOLEAN,
                Collections.singletonList(key), field, value);
    }

    @Override
    public String luaKeepIncrement(String key, Long num) {
        if(num == null) {
            return null;
        }
        String script = "local last = redis.call('get', KEYS[1]); " +
                "if not last or tonumber(ARGV[1]) > tonumber(last) then " +
                "redis.call('set', KEYS[1], ARGV[1]); " +
                "end; " +
                "return last; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), num);
    }

    @Override
    public Long luaDoubleAddUp(String key, Double val, boolean end) {
        if(val == null) {
            return null;
        }
        String script = "local v = redis.call('incrbyfloat', KEYS[1], ARGV[1]); " +
                "local t1, t2 = math.modf(v);" +
                "if ARGV[2] == 'true' then " +
                "redis.call('del', KEYS[1]);" +
                "else " +
                "redis.call('set', KEYS[1], t2);" +
                "end; " +
                "return t1;";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), val, end);
    }

    @Override
    public String couponsOperator(String key, long now, boolean reduce, CallStatus.Coupons value) {
        String script = "while true do " +
                " local r = redis.call('lpop', KEYS[1]); " +
                " if not r then break; end; " +
                " local json = cjson.decode(r); " +
                " if json.expireTime > tonumber(ARGV[1]) then " +
                " if ARGV[2] == 'true' then return r; end; " +
                " redis.call('lpush', KEYS[1], r); break; " +
                " end; " +
                " end; " +
                " local v = ARGV[3]; if v ~= '' then redis.call('rpush', KEYS[1], v); end; " +
                " return v; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), now, reduce,
                value == null ? "" : JSON.toJSONString(value));
    }

    @Override
    public void fixSizeListAdd(String key, String value, int limit) {
        String script = "local t = redis.call('llen', KEYS[1]);" +
                "if (t >= tonumber(ARGV[2])) then " +
                "redis.call('rpop', KEYS[1]); end; " +
                "redis.call('lpush', KEYS[1], ARGV[1]); ";
        RScript rscript = redissonClient.getScript();
        rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.BOOLEAN, Collections.singletonList(key), value, limit);
    }

    /**
     * 数据量不大的情况下,首页也可以考虑这种方式获取排序的数据。
     * @param key
     * @param language
     * @param country
     * @return
     */
    @Override
    public String sortTable(String key, String language, String country) {
        String script = "local t = redis.call('hgetall', KEYS[1]);\n" +
                "local arr = {};\n" +
                "for i, v in pairs(t) do\n" +
                "    if i % 2 == 0 then\n" +
                "        local j = cjson.decode(v)\n" +
                "        if j.language == ARGV[1] then j.languageEquals = 1 else j.languageEquals = 0 end;\n" +
                "        if j.country == ARGV[2] then j.countryEquals = 1 else j.countryEquals = 0 end;\n" +
                "        table.insert(arr, j)\n" +
                "    end    \n" +
                "end \n" +
                "table.sort(arr, function (a, b) \n" +
                "   local ta =  a.languageEquals + a.countryEquals; \n" +
                "   local tb =  b.languageEquals + b.countryEquals; \n" +
                "   if ta > 0 then ta = 1 end; \n" +
                "   if tb > 0 then tb = 1 end; \n" +
                "   if ta - tb == 0 then \n" +
                "      return a.createTime < b.createTime \n" +
                "   else " +
                "      return ta > tb end;\n" +
                "end)\n" +
                "return cjson.encode(arr); \n";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), language, country);
    }

    @Override
    public String hSetIsNull(String key, String field, String value) {
        String script = "local t = redis.call('hget', KEYS[1], ARGV[1]);\n" +
                "if t then return t; else redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return t; end;";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), field, value);
    }

    @Override
    public String setIsNull(String key, String value) {
        String script = "local t = redis.call('get', KEYS[1]);\n" +
                "if t then return t; else redis.call('set', KEYS[1], ARGV[1]); return t; end;";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), value);
    }

    @Override
    public String updateJson(String key, String field, long num, long limit) {
        String script = "local t = redis.call('get', KEYS[1]);\n" +
                "local j;\n" +
                "if t then j = cjson.decode(t); else j = cjson.decode(\"{}\"); end;\n" +
                "local n;\n" +
                "if j[ARGV[3]] then n = tonumber(j[ARGV[3]]); else n = 0 end;\n" +
                "local r = n + tonumber(ARGV[1]);\n" +
                "local limit = tonumber(ARGV[2]);\n" +
                "if r >= 0 and (limit < 0 or r <= limit) then j[ARGV[3]] = r; " +
                "redis.call('set', KEYS[1], cjson.encode(j)); end;\n" +
                "j[ARGV[3]] = r;" +
                "return cjson.encode(j);";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), num, limit, field);
    }

    @Override
    public String updateJson(String key, String field, String value) {
        String script = "local t = redis.call('get', KEYS[1]);\n" +
                "local j;\n" +
                "if t then j = cjson.decode(t); else j = cjson.decode(\"{}\"); end;\n" +
                "j[ARGV[1]] = ARGV[2]; " +
                "redis.call('set', KEYS[1], cjson.encode(j));\n" +
                "return cjson.encode(j);";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), field, value);
    }

    @Override
    public String hUpdateJson(String key, String uid, String field, long num, long limit) {
        String script = "local t = redis.call('hget', KEYS[1], ARGV[4]);\n" +
                "local j;\n" +
                "if t then j = cjson.decode(t); else j = cjson.decode(\"{}\"); end;\n" +
                "local n;\n" +
                "if j[ARGV[3]] then n = tonumber(j[ARGV[3]]); else n = 0 end;\n" +
                "local r = n + tonumber(ARGV[1]);\n" +
                "local limit = tonumber(ARGV[2]);\n" +
                "if r >= 0 and (limit < 0 or r <= limit) then j[ARGV[3]] = r; " +
                "redis.call('hset', KEYS[1], ARGV[4], cjson.encode(j)); end;\n" +
                "j[ARGV[3]] = r;" +
                "return cjson.encode(j);";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE,
                Collections.singletonList(key), num, limit, field, uid);
    }

    @Override
    public String mUpdateJson(String key, List<String> field, List<Number> num, List<Long> limit) {
        if(field == null || num == null || limit == null) {
            throw new RuntimeException("mUpdateJson param error, has null, field: " + field  + " num:" + num + " limit: " + limit);
        }
        field = field.stream().filter(Objects::nonNull).collect(Collectors.toList());
        num = num.stream().filter(Objects::nonNull).collect(Collectors.toList());
        limit = limit.stream().filter(Objects::nonNull).collect(Collectors.toList());
        if(field.size() > 100) {
            throw new RuntimeException("mUpdateJson operator field length not > 100!");
        }
        if(field.size() != num.size() || field.size() != limit.size()) {
            throw new RuntimeException("mUpdateJson param size error, fieldSize: " + field.size()  + " numSize:"
                    + num.size() + " limitSize: " + limit.size());
        }

        String script = "local t = redis.call('get', KEYS[1]);\n" +
                "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" +
                "if j[ARGV[i]] then n = tonumber(j[ARGV[i]]); else n = 0 end;\n" +
                "local r = n + tonumber(ARGV[i + 1]);\n" +
                "local limit = tonumber(ARGV[i + 2]);\n" +
                "if (r >= 0 or r > n) and (limit < 0 or r <= limit) then j[ARGV[i]] = r;\n" +
                "else j[ARGV[i]] = r; err = true; j['error'] = 1; end;\n" +
                "end; \n" +
                "local er = cjson.encode(j);\n" +
                "if err then return er;\n" +
                "else redis.call('set', KEYS[1], er); return er end;";
        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] = num.get(i);
            param[3 * i + 2] = limit.get(i);
        }

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

    @Override
    public void listDel(String key, String value) {
        String script = "local t = redis.call('LRANGE', KEYS[1], 0, -1); " +
                "if t then " +
                "local len = 0; " +
                "for i=1, #t do " +
                "   if (t[i] == ARGV[1]) then table.remove(t, i); len = len - 1; end;" +
                "   len = len + 1; " +
                "end; " +
                "redis.call('del', KEYS[1]); " +
                "if len > 0 then redis.call('RPUSH', KEYS[1], unpack(t)); end;" +
                "end;";
        RScript rscript = redissonClient.getScript();
        rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.BOOLEAN, Collections.singletonList(key), value);
    }

    @Override
    public List<Long> sAddAndExpire(String key, String field, long time, TimeUnit timeUnit) {
        String script = "local t = redis.call('sadd', KEYS[1], ARGV[1]);" +
                "local time = redis.call('ttl', KEYS[1]);" +
                "if not time or tonumber(time) <= 0 then redis.call('EXPIRE', KEYS[1], ARGV[2]); end;" +
                "return {t, redis.call('scard', KEYS[1])}; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.MULTI, Collections.singletonList(key), field, timeUnit.toMillis(time)/1000);
    }

    @Override
    public String hSetAndExpire(String key, String field, String value, long time, TimeUnit timeUnit) {
        String script = "local t = redis.call('hget', KEYS[1], ARGV[1]);" +
                "redis.call('hset', KEYS[1], ARGV[1], ARGV[2]);" +
                "local time = redis.call('ttl', KEYS[1]);" +
                "if not time or tonumber(time) <= 0 then redis.call('EXPIRE', KEYS[1], ARGV[3]); end;" +
                "return t; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.VALUE, Collections.singletonList(key), field, value, timeUnit.toMillis(time)/1000);
    }

    @Override
    public boolean zAddAndExpire(String key, String field, double score, long time, TimeUnit timeUnit) {
        String script = "local t = redis.call('zadd', KEYS[1], ARGV[1], ARGV[2]);" +
                "local time = redis.call('ttl', KEYS[1]);" +
                "if not time or tonumber(time) <= 0 then redis.call('EXPIRE', KEYS[1], ARGV[3]); end;" +
                "return t; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.BOOLEAN, Collections.singletonList(key), field, score, timeUnit.toMillis(time)/1000);
    }

    @Override
    public Long incrementAndExpire(String key, Long value, long time, TimeUnit timeUnit) {
        String script = "local t = redis.call('INCRBY', KEYS[1], ARGV[1]);" +
                "local time = redis.call('ttl', KEYS[1]);" +
                "if not time or tonumber(time) <= 0 then redis.call('EXPIRE', KEYS[1], ARGV[2]); end;" +
                "return t; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.INTEGER, Collections.singletonList(key), value, timeUnit.toMillis(time)/1000);
    }

    @Override
    public Long hIncrementAndExpire(String key, String field, Long score, long time, TimeUnit timeUnit) {
        String script = "local t = redis.call('HINCRBY', KEYS[1], ARGV[1], ARGV[2]);" +
                "local time = redis.call('ttl', KEYS[1]);" +
                "if not time or tonumber(time) <= 0 then redis.call('EXPIRE', KEYS[1], ARGV[3]); end;" +
                "return t; ";
        RScript rscript = redissonClient.getScript();
        return rscript.eval(RScript.Mode.READ_WRITE, script, RScript.ReturnType.INTEGER, Collections.singletonList(key), field, score, timeUnit.toMillis(time)/1000);
    }

}