高并发 共享资源 死锁 分布式锁 redisTemplate实现分布式锁 EvalSha is not supported in cluster environment

不羁的心 提交于 2020-07-28 17:09:16

也有不用回调函数直接调用脚本的版本,但是经过我的测试之后,发现报错EvalSha is not supported in cluster environment

上锁解锁的代码比较简单,也好理解。利用lua脚本解释redis命令,保证命令一次性运行成功,从而保证命令执行的原子性。

但是想和业务系统结合起来还是有难度的。特别是在本地事务中去使用的时候,需要结合业务特点,本地事务提交之后解锁也要成功。

/**
     * 获取锁
     * @param lockKey
     * @param value
     * @param expireTime:单位-秒
     * @return
     */
    public static boolean getLock(String lockKey, String requestId, int expireTime) {
        boolean ret = false;
        try {

            List<String> keys = new ArrayList<String>();
            keys.add(lockKey);
            List<String> args = new ArrayList<String>();
            args.add(requestId);
            args.add(expireTime + "");
            String script = "if redis.call('setNx',KEYS[1],ARGV[1])==1  then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end";

            Long result = (Long) redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection = connection.getNativeConnection();
                    // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
                    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
                        return (Long) ((JedisCluster) nativeConnection).eval(script, keys, args);
                    }

                    // 单机模式
                    else if (nativeConnection instanceof Jedis) {
                        return (Long) ((Jedis) nativeConnection).eval(script, keys, args);
                    }
                    return 0L;
                }
            });
            if (SUCCESS.equals(result)) {
                log.info("加锁成功...");
                return true;
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return ret;
    }

    /**
     * 释放锁
     * 
     * @param lockKey
     * @param value
     * @return
     */
    public static boolean releaseLock(String lockKey, String requestId) {
        boolean ret = false;
        try {
            List<String> keys = new ArrayList<String>();
            keys.add(lockKey);
            List<String> args = new ArrayList<String>();
            args.add(requestId);
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Long result = (Long) redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection = connection.getNativeConnection();
                    if (nativeConnection instanceof JedisCluster) {
                        return (Long) ((JedisCluster) nativeConnection).eval(script, keys, args);
                    }
                    else if (nativeConnection instanceof Jedis) {
                        return (Long) ((Jedis) nativeConnection).eval(script, keys, args);
                    }
                    return 0L;
                }
            });
            if (SUCCESS.equals(result)) {
                log.info("解锁成功...");
                return true;
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return ret;
    }

以上代码集群版本已经过测试。单机版未测试。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!