Redis分布式锁之实战

拥有回忆 提交于 2019-12-18 21:02:51

一、pom依赖

        <dependency>
            <groupId>tf56.redis</groupId>
            <artifactId>redis-client</artifactId>
            <version>1.0.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>servlet-api</artifactId>
                    <groupId>javax.servlet</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>gson</artifactId>
                    <groupId>com.google.code.gson</groupId>
                </exclusion>                
            </exclusions>
        </dependency>
<!-- 其他redis依赖 -->

二、MyCacheCloudRedisFactory工具类

 

package tf56.payOnlineService.util.redis;
​
import com.sohu.tv.builder.ClientBuilder;
import com.sohu.tv.cachecloud.client.basic.enums.RedisTypeEnum;
​
import org.apache.commons.lang.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.Transaction;
import tf56.common.redis.model.CommonConfigProp;
import tf56.common.util.PropUtil;
​
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
​
/**
 * CacheCloud Redis 云工厂
 * Created by Trying on 2017/4/10 16:46.
 */
public class MyCacheCloudRedisFactory {
​
    protected static final Logger log = LoggerFactory.getLogger(MyCacheCloudRedisFactory.class);
​
    /** 默认资源文件路径 */
    public static final String DEFAULT_PROP_FILEPATH = "config/CacheCloud.properties";
​
    /** 默认失效时间,单位:秒 */
    private static final int DEFAULT_EXPIRE_SECOND = 60;
​
    /** Jedis sentinel 连接池 */
    JedisSentinelPool jedisSentinelPool = null;
    
    private static final Long RELEASE_SUCCESS = 1L;
    
    private static final String LOCK_SUCCESS = "OK";
​
​
    /**
     * 默认构造函数,会自动从默认配置文件 ["config/CacheCloud.properties"] 读取必要参数
     */
    public MyCacheCloudRedisFactory() throws Exception {
        this.initWithProp(null, null);
    }
​
    /**
     * 指定资源文件路径的构造函数。具体参数的key沿用默认的。
     * @param propFilepath 资源文件路径
     * @throws Exception 异常时,无法构造实例
     */
    public MyCacheCloudRedisFactory(String propFilepath) throws Exception {
        this.initWithProp(propFilepath, null);
    }
​
    /**
     * 使用默认的资源文件路径
     * @param configProp 资源文件配置
     * @throws Exception 异常时,无法构造实例
     */
    public MyCacheCloudRedisFactory(CommonConfigProp configProp) throws Exception {
        this.initWithProp(null, configProp);
    }
​
    /**
     * 指定资源文件路径、资源文件配置信息
     * @param propFilepath 资源文件路径
     * @param configProp 资源文件配置
     * @throws Exception 异常时,无法构造实例
     */
    public MyCacheCloudRedisFactory(String propFilepath, CommonConfigProp configProp) throws Exception {
        this.initWithProp(propFilepath, configProp);
    }
​
    /**
     * 个性化构造函数
     * @param redisTypeEnum Redis类型,非null
     * @param cacheCloudAppId CacheCloud应用中的appId,非null,大于0的long型数据
     */
    public MyCacheCloudRedisFactory(RedisTypeEnum redisTypeEnum, Long cacheCloudAppId, String appKey) throws Exception {
        this.init(redisTypeEnum, cacheCloudAppId, appKey, null);
    }
​
​
    private void initWithProp(String propFilepath, CommonConfigProp configProp) throws Exception {
        if (propFilepath==null || propFilepath.trim().length()==0) {
            propFilepath = DEFAULT_PROP_FILEPATH;
        }
​
        if (configProp==null) {
            configProp = new CommonConfigProp();
        }
​
        String redisTypeKey = configProp.concatPrefixAndSuffix(configProp.getRedisTypeKey());
        String redisType = PropUtil.getPropValue(propFilepath, redisTypeKey, null);
        String appIdKey = configProp.concatPrefixAndSuffix(configProp.getAppIdKey());
        String appIdStr = PropUtil.getPropValue(propFilepath, appIdKey, null);
        String appKeyKey = configProp.concatPrefixAndSuffix(configProp.getAppKeyKey());
        String appkeyStr = PropUtil.getPropValue(propFilepath, appKeyKey, null);
​
​
        RedisTypeEnum redisTypeEnum = null;
        long appId = 0;
        try {
            if (redisType==null || redisType.trim().length()==0) {
                redisTypeEnum = RedisTypeEnum.SENTINEL;
            } else {
                redisTypeEnum = RedisTypeEnum.valueOf(redisType);
            }
​
            appId = Long.parseLong(appIdStr);
        } catch (Exception e) {
            String msg = propFilepath + "{"+redisTypeKey + ":" + redisType + ", " + appIdKey + ":" + appIdStr + "}. \n";
            log.warn(msg + e.getMessage());
            throw new Exception(msg);
        }
​
        if (StringUtils.isBlank(appkeyStr)) {
            String msg = propFilepath + "{"+appKeyKey + ":" + appkeyStr +"}. \n Invalid param appKey !";
            log.warn(msg);
            throw new Exception(msg);
        }
​
​
        /* 连接池配置 */
        GenericObjectPoolConfig poolConfig = null;
        try {
            String minIdleKey = configProp.concatPrefixAndSuffix(configProp.getPoolMinIdleKey());
            String minIdleStr = PropUtil.getPropValue(propFilepath, minIdleKey, null);
            String maxIdleKey = configProp.concatPrefixAndSuffix(configProp.getPoolMaxIdleKey());
            String maxIdleStr = PropUtil.getPropValue(propFilepath, maxIdleKey, null);
            String maxTotalKey = configProp.concatPrefixAndSuffix(configProp.getPoolMaxTotalKey());
            String maxTotalStr = PropUtil.getPropValue(propFilepath, maxTotalKey, null);
​
            int minIdle = 0;
            int maxIdle = 0;
            int maxTotal = 0;
            if (minIdleStr != null)
                minIdle = Integer.parseInt(minIdleStr);
            if (maxIdleStr != null)
                maxIdle = Integer.parseInt(maxIdleStr);
            if (maxTotalStr != null)
                maxTotal = Integer.parseInt(maxTotalStr);
​
            poolConfig = new GenericObjectPoolConfig();
            if (minIdle>0) {
                poolConfig.setMinIdle(minIdle);
            }
            if (maxIdle>0 && maxIdle>minIdle) {
                poolConfig.setMaxIdle(maxIdle);
            }
            if (maxTotal>0) {
                poolConfig.setMaxTotal(maxTotal);
            }
        } catch (Exception e) {
            String msg = "Read pool config ERROR!";
            log.warn(msg, e);  // 连接池配置信息读取异常时,将只记录日志警告,并使用默认配置。而不抛异常。
        }
​
        this.init(redisTypeEnum, appId, appkeyStr, poolConfig);
    }
​
​
    /**
     * 初始化
     * @param redisTypeEnum Redis类型,非null
     * @param cacheCloudAppId CacheCloud应用中的appId,非null,大于0的long型数据
     */
    private void init(RedisTypeEnum redisTypeEnum, Long cacheCloudAppId, String appKey, GenericObjectPoolConfig poolConfig) throws Exception {
        if (redisTypeEnum==null || (cacheCloudAppId==null || cacheCloudAppId<=0)) {
            String msg = "Invalid input params:{redisTypeEnum:"+redisTypeEnum + ", cacheCloudAppId:"+cacheCloudAppId;
            log.warn(msg);
            throw new Exception(msg);
        }
​
        if (poolConfig==null) {  // 默认连接池配置
            poolConfig = new GenericObjectPoolConfig();
            poolConfig.setMinIdle(100);
            poolConfig.setMaxIdle(1000);
            poolConfig.setMaxTotal(10000);
        }
​
        switch (redisTypeEnum) {
            case SENTINEL:
                default:
                    jedisSentinelPool = this.buildJedisSentinelPool(cacheCloudAppId, appKey, poolConfig);
        }
    }
​
​
    /**
     * 构建 jedis 的 sentinel 连接池
     * @param cacheCloudAppId CacheCloud 平台中的应用ID
     * @param poolConfig jedis连接池设置
     * @return 连接池
     */
    private JedisSentinelPool buildJedisSentinelPool(Long cacheCloudAppId, String appkey, GenericObjectPoolConfig poolConfig) {
        if (cacheCloudAppId==null || cacheCloudAppId<=0) {
            return null;
        }
​
        if (poolConfig==null) {
            poolConfig = new GenericObjectPoolConfig();
        }
​
        return ClientBuilder.redisSentinel(cacheCloudAppId)
                .setConnectionTimeout(1000)
                .setSoTimeout(1000)
                .setPoolConfig(poolConfig)
                .buildWithSafeCheck(true, appkey);
    }
​
​
​
    /**
     * 测试服务器是否正常
     *
     * @return 正常情况下,返回:PONG
     */
    public String ping() {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.ping();
        } catch (Exception e) {
            log.error("Redis get ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
    /**
     * 对 key 增加 1
     *
     * @param key 键
     * @return 执行结果
     */
    public Long incr(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.incr(key);
        } catch (Exception e) {
            log.error("Redis incr ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
    /**
     * 对 key 增加 number。(如果number为负数,则为减少)
     *
     * @param key 键
     * @param number 长整形增量
     * @return 执行结果
     */
    public Long incrByLong(final String key, final Long number) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return -1L;
        }
​
        if (key==null || number==null) {
            log.warn("Key or number is null !");
            return -1L;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.incrBy(key, number);
        } catch (Exception e) {
            log.error("Redis incrBy ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return -1L;
    }
​
    /**
     * 对 key 增加 number。(如果number为负数,则为减少)
     *
     * @param key 键
     * @param number 浮点型增量
     * @return 执行结果
     */
    public Double incrByDouble(final String key, final Double number) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null || number==null) {
            log.warn("Key or number is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.incrByFloat(key, number);
        } catch (Exception e) {
            log.error("Redis incrByFloat ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
​
​
    private long parseLong(String data) {
        long rst = 0;
        try {
            rst = Long.parseLong(data);
        } catch (Exception e) {
            log.error("Trying ERROR!", e);
        }
​
        return rst;
    }
​
​
​
    /**
     * 设置字符串缓存,使用默认存活时长60秒
     *  此方法实现有bug,失效时间可能不会起作用
     * @param key 键
     * @param value 值
     */
    public void set(String key, String value) {
        this.set(key, value, DEFAULT_EXPIRE_SECOND);
    }
​
    /**
     * 设置缓存,并指定过期时间
     * @param key
     * @param value
     * @param second 最大48小时
     */
    public void setEx(final String key,final String value,int second) {
        if (second > 48 * 3600) {
            second = 48 * 3600;
        }
        Jedis jedis = this.getJedisConnection();
        jedis.setex(key, second, value);
    }
​
    /**
     * 验证缓存的key 是否存在
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        if (key == null || key.equals("")) {
            return Boolean.FALSE;
        }
        return this.jedisSentinelPool.getResource().exists(key);
    }
​
    /**
     * 设置字符串缓存
     *
     * @param key 键
     * @param value 值
     * @param liveTime 存活时长,单位:秒。如果持久化保存,就设置为-1
     */
    public void set(String key, String value, int liveTime) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return;
        }
​
        if (key==null || value == null) {
            log.warn("Key or Value is null :key="+key+"---------value="+value);
            return;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.set(key, value);
            if (liveTime>0) {
                jedis.expire(key, liveTime);
            }
        } catch (Exception e) {
            log.error("Redis set ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
    }
​
​
    /**
     * 设置指定key的存活时长。<br/>
     * 一般用于再次延长key的存活时长。
     *
     * @param key 键
     * @param liveTime 存活时长,单位:秒。如果持久化保存,就设置为-1
     */
    public void expire(String key, int liveTime) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return;
        }
​
        if (key==null || liveTime<=0) {
            log.warn("Key or Value is null :key="+key+", liveTime="+liveTime);
            return;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.expire(key, liveTime);
        } catch (Exception e) {
            log.error("Redis set ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
    }
​
​
    /**
     * 读取字符串缓存
     *
     * @param key 键
     * @return 缓存的字符串值
     */
    public String get(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.get(key);
        } catch (Exception e) {
            log.error("Redis get ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
​
    /**
     * 删除指定的缓存key
     *
     * @param keys 待删除的key
     * @return 执行结果
     */
    public long del(final String... keys) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return 0;
        }
​
        if (keys==null || keys.length==0) {
            log.warn("Keys is null !");
            return 0;
        }
​
        long rst = 0;
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            rst = jedis.del(keys);
        } catch (Exception e) {
            log.error("Redis get ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return rst;
    }
​
​
    /**
     * hash 类型的 redis 数据缓存。默认存活60秒。
     * @param key redis 的缓存 key
     * @param field 缓存的 hash 数据的字段名
     * @param value 缓存的 hash 数据的字段值
     */
    public void hset(String key, String field, String value) {
        this.hset(key, field, value, DEFAULT_EXPIRE_SECOND);
    }
​
    /**
     * hash 类型的 redis 数据缓存
     * @param key redis 的缓存 key
     * @param field 缓存的 hash 数据的字段名
     * @param value 缓存的 hash 数据的字段值
     * @param liveTime 存活时长,秒
     */
    public void hset(String key, String field, String value, int liveTime) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return;
        }
​
        if (key==null || field==null || value == null) {
            log.warn("Input param is null :key="+key+", field="+field+", value="+value);
            return;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.hset(key, field, value);
            if (liveTime>0) {
                jedis.expire(key, liveTime);
            }
        } catch (Exception e) {
            log.error("Redis hset ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
    }
​
​
    /**
     * 读取hash缓存
     *
     * @param key 键
     * @return hash数据属性值
     */
    public String hget(final String key, final String field) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.hget(key, field);
        } catch (Exception e) {
            log.error("Redis hget ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
​
    /**
     * hash 类型的 redis 数据缓存。同时缓存多个属性。批量缓存。
     * 默认存活60秒。
     *
     * @param key redis 的缓存 key
     * @param hash 缓存的 hash 数据。字段名:字段值
     */
    public void hmset(String key, Map<String, String> hash) {
        this.hmset(key, hash, DEFAULT_EXPIRE_SECOND);
    }
​
    /**
     * hash 类型的 redis 数据缓存。同时缓存多个属性。批量缓存。
     *
     * @param key redis 的缓存 key
     * @param hash 缓存的 hash 数据。字段名:字段值
     * @param liveTime 存活时长,秒
     */
    public void hmset(String key, Map<String, String> hash, int liveTime) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return;
        }
​
        if (key==null || hash == null || hash.size()==0) {
            log.warn("Input param is null :key="+key+", hash="+hash);
            return;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.hmset(key, hash);
            if (liveTime>0) {
                jedis.expire(key, liveTime);
            }
        } catch (Exception e) {
            log.error("Redis hmset ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
    }
​
    /**
     * 批量读取hash缓存指定的属性值
     *
     * @param key 键
     * @param field hash数据的属性数组。
     * @return hash数据的属性值列表。
     */
    public List<String> hmget(final String key, final String... field) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null || field==null) {
            log.warn("Key or field is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.hmget(key, field);
        } catch (Exception e) {
            log.error("Redis hmget ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
    /**
     * 批量读取hash缓存
     *
     * @param key 键
     * @return hash数据的值。
     */
    public Map<String, String> hgetAll(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.hgetAll(key);
        } catch (Exception e) {
            log.error("Redis hgetAll ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return null;
    }
​
​
    /**
     * 批量读取hash缓存
     *
     * @param key 键
     * @return hash数据的值。
     */
    public void hdel(String key, String... field) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return;
        }
​
        if (key==null || field==null) {
            log.warn("Key or field is null !");
            return;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            jedis.hdel(key, field);
        } catch (Exception e) {
            log.error("Redis hdel ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
    }
​
​
    /**
     * hash 扫描 。
     * 注意:原 scanHashs 方法的调用,返回的类型是spring-dto-bean包中的,这里需要切换!!!
     *
     * @param key 指定 hash 的 key
     * @param pattern 正则
     * @param count 统计量
     * @return 扫描结果
     */
    public ScanResult<Map.Entry<String, String>> hscan(String key, String pattern, Integer count) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        ScanResult<Map.Entry<String, String>> scanResult = null;
        Jedis jedis = null;
​
        try {
            jedis = jedisSentinelPool.getResource();
​
            ScanParams scanParams = null;
            if (pattern!=null || count!=null) {
                scanParams = new ScanParams();
            }
            if (count!=null) {
                scanParams.count(count);
            }
            if (pattern!=null) {
                scanParams.match(pattern);
            }
​
            if (scanParams!=null) {
                scanResult = jedis.hscan(key, ScanParams.SCAN_POINTER_START, scanParams);
            } else {
                scanResult = jedis.hscan(key, ScanParams.SCAN_POINTER_START);
            }
        } catch (Exception e) {
            log.error("Redis hscan ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return scanResult;
    }
​
​
    /**
     * 集合添加元素
     *
     * @param key 集合的key
     * @param members 待添加的集合中的元素
     * @return 执行结果
     */
    public Long sadd(final String key, final String... members) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null || members==null || members.length==0) {
            log.warn("Key or members is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.sadd(key, members);
        } catch (Exception e) {
            log.error("Redis sadd ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
​
    /**
     * 统计集合中元素数
     *
     * @param key 集合的key
     * @return 执行结果
     */
    public Long scard(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.scard(key);
        } catch (Exception e) {
            log.error("Redis scard ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
​
​
    /**
     * 查询集合中的元素
     *
     * @param key 集合的key
     * @return 集合元素
     */
    public Set<String> smembers(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.smembers(key);
        } catch (Exception e) {
            log.error("Redis smembers ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
​
​
    /**
     * 从队列左侧推入
     *
     * @param key 队列的key
     * @param values 待推入的队列元素值
     * @return 执行结果
     */
    public Long lpush(final String key,final String... values) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null || values==null) {
            log.warn("Key or values is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.lpush(key, values);
        } catch (Exception e) {
            log.error("Redis lpush ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
​
    /**
     * 从队列左侧弹出
     *
     * @param key 队列的key
     * @return 弹出的元素
     */
    public String lpop(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.lpop(key);
        } catch (Exception e) {
            log.error("Redis lpop ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
​
    /**
     * 从队列右侧弹出
     *
     * @param key 队列的key
     * @return 弹出的元素
     */
    public String rpop(final String key) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (key==null) {
            log.warn("Key is null !");
            return null;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            return jedis.rpop(key);
        } catch (Exception e) {
            log.error("Redis rpop ERROR!", e);
        } finally {
            if(jedis!=null)
                jedis.close();
        }
​
        return null;
    }
    
    public String lock(String lockName, long acquireTimeout, long lockTimeout) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (lockName==null) {
            log.warn("Key is null !");
            return null;
        }
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            String identifier = UUID.randomUUID().toString();
            String lockKey = "lock:" + lockName;
            int lockExpire = (int)(lockTimeout / 1000);
​
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {
                if (jedis.setnx(lockKey, identifier) == 1){
                    jedis.expire(lockKey, lockExpire);
                    return identifier;
                }
                if (jedis.ttl(lockKey) == -1) {
                    jedis.expire(lockKey, lockExpire);
                }
​
                try {
                    Thread.sleep(1);
                }catch(InterruptedException ie){
                    Thread.currentThread().interrupt();
                }
            }
​
            // null indicates that the lock was not acquired
            return null;
            
        } catch (Exception e) {
            log.error("Redis lock ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
        return null;
    }
    
    public boolean unlock(final String lockName,final String identifier) {
        if (jedisSentinelPool==null) {
            String msg = "jedisSentinelPool is null !";
            log.error(msg);
            return false;
        }
​
        if (lockName==null) {
            String msg = "Key is null !";
            log.warn(msg);
            return false;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
​
            String lockKey = "lock:" + lockName;
            
            while (true){
                jedis.watch(lockKey);
                if (identifier.equals(jedis.get(lockKey))){
                    Transaction trans = jedis.multi();
                    trans.del(lockKey);
                    List<Object> results = trans.exec();
                    if (results == null){
                        continue;
                    }
                    return true;
                }
                jedis.unwatch();
                break;
            }
            return false;
        } catch (Exception e) {
            String msg = "Redis unlock ERROR!";
            log.error(msg, e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return false;
    }
    
    public String lockWithLua(String lockName, long acquireTimeout, long lockTimeout) {
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        if (lockName==null) {
            log.warn("Key is null !");
            return null;
        }
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            
            String identifier = UUID.randomUUID().toString();
            String lockKey = "lock:" + lockName;
            int lockExpire = (int)(lockTimeout / 1000);
​
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {
                String script = "if redis.call('exists', KEYS[1]) == 0 then return redis.call('setex', KEYS[1], unpack(ARGV)) end";
                Object result = jedis.eval(script, 1, lockKey, String.valueOf(lockExpire),identifier);
                if(LOCK_SUCCESS.equals(result)){
                    return identifier;
                }
                try {
                    Thread.sleep(1);
                }catch(InterruptedException ie){
                    Thread.currentThread().interrupt();
                }
            }
​
            // null indicates that the lock was not acquired
            return null;
            
        } catch (Exception e) {
            log.error("Redis lock ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
        return null;
    }
    
    public boolean unlockWithLua(final String lockName,final String identifier) {
        if (jedisSentinelPool==null) {
            String msg = "jedisSentinelPool is null !";
            log.error(msg);
            return false;
        }
​
        if (lockName==null) {
            String msg = "Key is null !";
            log.warn(msg);
            return false;
        }
​
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
​
            String lockKey = "lock:" + lockName;
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, 1,lockKey, identifier);
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        } catch (Exception e) {
            String msg = "Redis unlock ERROR!";
            log.error(msg, e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
​
        return false;
    }
​
    /**
     * 增加redis缓存,作为锁定对象
     * @param lockTarget 锁定目标对象
     * @param expire 过期时间/锁定时长,单位/秒
     * @return
     */
    public boolean tryLock(String lockTarget, int expire) {
        if (lockTarget==null) {
            log.warn("Key is null !");
            return false;
        }
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
            String script = "if redis.call('exists', KEYS[1]) == 0 then return redis.call('setex', KEYS[1], unpack(ARGV)) end";
            Object result = jedis.eval(script, 1, lockTarget, String.valueOf(expire), lockTarget);
            if(LOCK_SUCCESS.equals(result)){
                return true;
            }
        } catch (Exception e) {
            log.error("Redis lock ERROR!", e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
        return false;
    }
​
    /**
     * 删除redis缓存
     * 解锁目标对象
     * @param lockTarget 待解锁目标对象
     * @return
     */
    public boolean tryUnlock(String lockTarget) {
        if (lockTarget==null) {
            log.warn("Key is null !");
            return false;
        }
        Jedis jedis = null;
        try {
            jedis = jedisSentinelPool.getResource();
​
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, 1, lockTarget, lockTarget);
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        } catch (Exception e) {
            String msg = "Redis unlock ERROR!";
            log.error(msg, e);
        } finally {
            if(jedis!=null) {
                jedis.close();
            }
        }
        return false;
    }
​
​
    //获取Jedis
    public Jedis getJedisConnection(){
        if (jedisSentinelPool==null) {
            log.warn("jedisSentinelPool is null !");
            return null;
        }
​
        Jedis jedis = jedisSentinelPool.getResource();
        return jedis;
    }
​
​
​
}
​

 

RedisUtil.java

package tf56.payOnlineService.util.redis;
​
public class RedisUtil extends MyCacheCloudRedisFactory {
    private static RedisUtil redisUtil = null;
​
    static {
        try {
            redisUtil = new RedisUtil();
        } catch (Exception e) {
            log.error("Init common redis client ERROR !", e);
        }
    }
​
    /**
     * 默认构造函数,会自动从默认配置文件 ["config/CacheCloud.properties"] 读取必要参数
     */
    private RedisUtil() throws Exception {
    }
​
​
    public static RedisUtil getInstance() {
        return redisUtil;
    }
​
}

 

使用示例

可根据实际业务场景自定义返回,或者跑异常....

if (!RedisUtil.getInstance().tryLock(lock, 5)) { // expire
    return ResultUtils.failed("当前订单列表含有处理中,请等待处理结果或者5秒后重试");
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!