Jedis分布式锁实际应用笔记

前几日做了一个类似论坛的功能实现,话不多说,上代码

工具类 JedisUtil

@Component
public class JedisUtil {

    private static JedisPool jedisPool;
    private static String prefix = "";
    private static String redisHost;
    private static Integer redisPort;
    private static final String LOCK_SUCCESS = "OK";
    private static final Long RELEASE_SUCCESS = 1L;

    @Value("${jedisPrefix}")
    public void setJedisClusterPrefix(String jedisClusterPrefix) {
        if (ToolUtil.isNotEmpty(jedisClusterPrefix)) {
            prefix = jedisClusterPrefix + "_";
        }
    }

    @Value("${jedisHostList}")
    private void initRedisHostInfo(String hosts) {
        String[] split = hosts.split(":");
        redisHost = split[0];
        redisPort = Convert.toInt(split[1]);
        redisPoolFactory();
    }

    /**
     * Jedis初始化
     *
     * @since 2020-02-26
     */
    public static void redisPoolFactory() {
        //连接超时
        //读取数据超时
        Integer timeout = 10000;
        //最大连接数
        Integer maxTotal = 50;
        //连接阻塞时间-1为无限等待
        Long maxWait = -1L;
        //最大空闲连接
        Integer maxIdle = 10;
        //最小空闲连接
        Integer minIdle = 5;
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWait);
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout, pwd);
    }

    /**
     * 获取字符串
     *
     * @since 202-02-26
     */
    public static String getString(String key, int... second) {
        Jedis jedis = jedisPool.getResource();
        String res = "";
        key = prefix + key;
        try {
            res = jedis.get(key);
            expireInside(jedis, key, second);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            jedis.close();
        }
    }

    /**
     * 写入字符串
     *
     * @since 2020-02-26
     */
    public static void setString(String key, String data, int... second) {
        Jedis jedis = jedisPool.getResource();
        try {
            key = prefix + key;
            jedis.set(key, data);
            expireInside(jedis, key, second);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            jedis.close();
        }
    }

    /**
     * 设置key的时间
     *
     * @since 2020-02-26
     */
    public static Long expire(String key, Integer second) {
        Jedis jedis = jedisPool.getResource();
        key = prefix + key;
        try {
            return jedis.expire(key, second);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            jedis.close();
        }
    }



    /**
     * Redis分布式锁判定
     *
     * @since 2020-02-26
     */
    public static Object eval(String key, List<String> keys, List<String> args) {
        Jedis jedis = jedisPool.getResource();
        key = prefix + key;
        try {
            return jedis.eval(key, keys, args);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            jedis.close();
        }
    }

    /**
     * 延长key的时间
     *
     * @since 2020-02-26
     */
    private static void expireInside(Jedis jedis, String key, int... second) {
        if (ToolUtil.isNotEmpty(key) && second.length > 0) {
            Integer temp = 1800;
            temp = second[0];
            jedis.expire(key, (int) (temp + Math.random() * (temp * 2)));
        }
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey    锁
     * @param requestId  请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetLock(String lockKey, String requestId, int expireTime) {
        Jedis jedis = jedisPool.getResource();
        try {
            lockKey = prefix + lockKey;
            SetParams setParams = new SetParams();
            String result = jedis.set(lockKey, requestId, setParams.nx().px(expireTime));
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            jedis.close();
        }
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseLock(String lockKey, String requestId) {
        Jedis jedis = jedisPool.getResource();
        try {
            lockKey = prefix + lockKey;
            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, Collections.singletonList(lockKey), Collections.singletonList
                    (requestId));
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            jedis.close();
        }
    }
}

实际代码调用

        //uuid
        String requestId = UuidUtils.getUUID();
        //分布式锁
        String topicLock = "topicLock_" + topicId;
        boolean flag = true;
        if (条件) {
            //循环获取锁  次数自己定义
            for (int i = 0; i < 3; i++) {
                //传入参数   key  uuid   存活时间
                boolean keySuccess = JedisUtil.tryGetLock(topicLock, requestId, 10);
                //如果获取到锁
                if (keySuccess) {
                    //进行逻辑操作
                      xxxzzzzxxxxx
                    //释放锁  或者超过10秒自己释放
                    JedisUtil.releaseLock(topicLock, requestId);
                    break;
                }
                Thread.sleep(300L);
            }
        }

这是在jedis基础上自己封装的分布式锁,跟redistemplate分布式锁一样存在集群中锁异常关闭导致重复获取锁的问题,简单业务可以应用,如果业务庞大且服务器不稳定,建议选择zk做分布式锁

posted @ 2020-08-14 17:22  大日很忧伤  阅读(375)  评论(0)    收藏  举报