Jedis Util

package com.iclass.esb.engine.cache.redis;


import com.iclass.esb.engine.cache.ESBCache;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;


/**
 * Created by xxxx on 2015/9/11.
 */
public class RedisCache implements ESBCache {


    private ShardedJedisPool jedisPool;
    public static final  long   DEFAULT_TIMEOUT   = 30 * 60 * 1000;
    private static final int    DEFAULT_WAIT_TIME = 5;//同步鎖的默認等待時間
    private final static Logger LOGGER            = LoggerFactory.getLogger(RedisCache.class);
    private final static int    DEFAULT_EXPIRE    = 2 * 60 * 60;




    @Override
    public <T> T get(String key) {
        Object result = new Executor<Object>(jedisPool.getResource(), key) {
            @Override
            Object excute(ShardedJedis jedis, String key) {
                byte[] keyBytes = SerializationUtils.serialize(key);
                byte[] valueBytes = jedis.get(keyBytes);
                return SerializationUtils.deserialize(valueBytes);
            }
        }.getResult();
        return result == null ? null : (T) result;
    }


    public <T> T getByLock(String key) {
        Object result = new Executor<Object>(jedisPool.getResource(), key) {
            @Override
            Object excute(ShardedJedis jedis, String key) {
                lock(key);
                LOGGER.info("對{}進行加鎖", key);
                byte[] keyBytes = SerializationUtils.serialize(key);
                byte[] valueBytes = jedis.get(keyBytes);
                return SerializationUtils.deserialize(valueBytes);
            }
        }.getResult();
        return result == null ? null : (T) result;
    }


    @Override
    public boolean set(String key, final Object value) {
        ShardedJedis jedis = jedisPool.getResource();
        byte[] keyBytes = SerializationUtils.serialize(key);
        byte[] valueBytes = SerializationUtils.serialize(value);
        jedis.set(keyBytes, valueBytes);
        jedis.expire(keyBytes, DEFAULT_EXPIRE);
        jedisPool.returnResourceObject(jedis);
        return true;
    }


    @Override
    public boolean set(String key, Object value, int expire) {
        ShardedJedis jedis = jedisPool.getResource();
        byte[] keyBytes = SerializationUtils.serialize(key);
        byte[] valueBytes = SerializationUtils.serialize(value);
        jedis.set(keyBytes, valueBytes);
        jedis.expire(keyBytes, expire);
        jedisPool.returnResourceObject(jedis);
        return true;
    }




    @Override
    public void lock(String key, long timeout) {
        long orginalTimeout = timeout;
        while (timeout >= 0) {
            ShardedJedis shardedJedis = this.getJedisPool().getResource();
            long expires = System.currentTimeMillis() + timeout + 1;
            String expiresStr = String.valueOf(expires);


            if (shardedJedis.setnx(key + "_lock", expiresStr) == 1) {
                shardedJedis.expire(key + "_lock", Integer.valueOf("" + timeout));
                this.getJedisPool().returnResourceObject(shardedJedis);
                return;
            }


            String currentValueStr = shardedJedis.get(key + "_lock");
            if (StringUtils.isEmpty(currentValueStr)) {
                this.getJedisPool().returnResourceObject(shardedJedis);
                continue;
            }
            if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
                LOGGER.info("key:{} 已過鎖過期時間將強制獲取鎖,並重置鎖時間。", key);
                String oldValueStr = shardedJedis.getSet(key + "_lock", expiresStr);
                if (currentValueStr.equals(oldValueStr)) {
                    expires = System.currentTimeMillis() + orginalTimeout + 1;
                    expiresStr = String.valueOf(expires);
                    shardedJedis.set(key + "_lock", expiresStr);
                    this.getJedisPool().returnResourceObject(shardedJedis);
                    return;
                }
                else{
                    shardedJedis.set(key+"_lock",oldValueStr);
                    timeout = orginalTimeout;
                }
            }
            timeout -= 10;
            try {
                this.getJedisPool().returnResourceObject(shardedJedis);
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public void lockTransaction(String key, String transactionToken) {
        lockTransaction(key, DEFAULT_TIMEOUT, transactionToken);
    }


    @Override
    public void lockTransaction(String key, long timeout, String transactionToken) {
        if (StringUtils.isEmpty(transactionToken)){
            lock(key,timeout);
            return;
        }
        String lockTransactionToken = get(key + "-lock-transaction-token");
        if (StringUtils.isNoneBlank(lockTransactionToken)) {
            if (StringUtils.equals(lockTransactionToken, transactionToken)) {
                return;
            }
        }
        lock(key, timeout);
        while (true) {
            try {
                lockTransactionToken = get(key + "-lock-transaction-token");
                if (StringUtils.isEmpty(lockTransactionToken)) {
                    set(key + "-lock-transaction-token", transactionToken, DEFAULT_EXPIRE);
                    return;
                }
                Thread.sleep(10);
            } catch (InterruptedException e) {
                LOGGER.error("release transaction lock token error", e);
            }
        }
    }


    @Override
    public void unlockTransaction(String key) {
        unlock(key);
        evict(key + "-lock-transaction-token");
    }


    @Override
    public void lock(String key) {
        lock(key, DEFAULT_TIMEOUT);
    }




    @Override
    public void unlock(String key) {
        ShardedJedis jedis = jedisPool.getResource();
        try {
            LOGGER.info("key:{}已清除鎖成功", key);
            jedis.del(key + "_lock");
        } finally {
            jedisPool.returnResourceObject(jedis);
        }
    }


    @Override
    public boolean evict(String key) {
        ShardedJedis jedis = jedisPool.getResource();
        try {
            jedis.del(SerializationUtils.serialize(key));
        } finally {
            jedisPool.returnResourceObject(jedis);
        }
        return true;
    }




    abstract class Executor<T> {
        private ShardedJedis jedis = null;
        private String key;


        public Executor(ShardedJedis jedis, String key) {
            this.jedis = jedis;
            this.key = key;
        }


        abstract T excute(ShardedJedis jedis, String key);


        public T getResult() {
            T result = null;
            try {
                //1.判斷key有沒有鎖
                while (StringUtils.isNoneEmpty(jedis.get(key + "_lock"))) {
                    Thread.sleep(DEFAULT_WAIT_TIME);
                }
                //2.沒有鎖才能繼續操作
                result = excute(jedis, key);
            } catch (Exception e) {
                jedisPool.returnResourceObject(jedis);
                throw new RuntimeException("Redis命令執行失敗", e);
            } finally {
                jedisPool.returnResourceObject(jedis);
            }
            return result;
        }
    }


    public ShardedJedisPool getJedisPool() {
        return jedisPool;
    }


    public void setJedisPool(ShardedJedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章