• 简单分布式锁的实现


    1. 定义接口

    public interface RedisLock {
        String OK_CODE = "OK";
        String OK_MULTI_CODE = "+OK";
    
        /**
         * 加锁
         *
         * @param lockKey 锁key
         * @param seconds 过期时间
         * @return true:成功获取锁;false:没有获取到锁
         */
        Result<String> lock(final String lockKey, final int seconds);
    
        /**
         * 解锁
         *
         * @param key 锁key
         * @return true:成功解锁;
         */
        boolean unlock(String key,String value);
    
        default boolean isStatusOk(String status) {
            return (status != null) && (OK_CODE.equals(status) || OK_MULTI_CODE.equals(status));
        }
    }

    2.

    @Service
    @Slf4j
    public class DefaultRedisLock implements RedisLock {
    
        @Autowired
        private RedisResource redisService;
    
    
        @Override
        public Result<String> lock(String lockKey, int seconds) {
            String value = UUID.randomUUID().toString();
            if (isStatusOk(redisService.getJedisCluster().set(lockKey, value, "NX", "EX", seconds))) {
                return Result.buildSuccessResult(value);
            }
    
            return Result.ERROR_STRING_RESULT;
        }
    
        @Override
        public boolean unlock(String lockKey, String value) {
            return redisService.compareAndDelete(lockKey, value);
        }

    3..

    @Service
    @Slf4j
    public class RedisResource {
    
        @Autowired
        private JedisCluster redisService;
    
        public JedisCluster getJedisCluster() {
            return redisService;
        }
    
       /**
         * Lua脚本 (比较相等后删除)
         */
        private static final String LUA_SCRIPT_COMPARE_AND_DELETE =
                "local current = redis.call('get', KEYS[1]);
    " +
                        "if (nil == current) then
    " +
                        "    return 1;
    " +
                        "end
    " +
                        "if (current == ARGV[1]) then
    " +
                        "    redis.call('del', KEYS[1]);
    " +
                        "    return 1;
    " +
                        "end
    " +
                        "return 0;";
    
        private static String LUA_SCRIPT_COMPARE_AND_DELETE_SHA1;
    
        static {
            LUA_SCRIPT_COMPARE_AND_DELETE_SHA1 = SHA1.encode(LUA_SCRIPT_COMPARE_AND_DELETE);
            
        }
    
    
      public boolean compareAndDelete(String key, String value) {
            return execLunaScript(new RedisScript(LUA_SCRIPT_COMPARE_AND_DELETE, LUA_SCRIPT_COMPARE_AND_DELETE_SHA1),
                    1,
                    new String[]{key, value},
                    (o) -> processResult(o));
        }
    
        private static boolean processResult(Object o) {
            return o == null ? false : isStatusOk(o.toString());
        }
    
        static final String OK_CODE = "1";
        static boolean isStatusOk(String status) {
            return (status != null) && (OK_CODE.equals(status) );
        }
    
        /**
         * 执行lua脚本
         *
         * @param redisScriptObj 脚本
         * @param keyCount       key总数量
         * @param param          参数数组(包含key及参数)
         */
        private <T> T execLunaScript(RedisScript redisScriptObj, int keyCount, String[] param,
                Function<Object, T> function) {
            try {
                return function.apply(redisService.evalsha(redisScriptObj.sha1, keyCount, param));
    
            } catch (redis.clients.jedis.exceptions.JedisNoScriptException ex) {
                try {
                    return function.apply(redisService.eval(redisScriptObj.script, keyCount, param));
                } catch (Exception e) {
                    log.error("执行redis脚本异常2!", e);
                    return null;
                }
            } catch (Exception ex) {
                log.error("执行redis脚本异常!", ex);
                return null;
            }
        }
    
        static class RedisScript {
            private String script;
            private String sha1;
    
            public RedisScript(String script) {
                this(script, SHA1.encode(script));
            }
    
            public RedisScript(String script, String sha1) {
                this.script = script;
                this.sha1 = sha1;
            }
        }
    }
  • 相关阅读:
    [NOI2021] 路径交点
    CF1188D Make Equal
    CF1349F1 Slime and Sequences
    CF1067D Computer Game
    Dcat Admin安装
    PHP 中提示undefined index如何解决(多种方法)
    Git 常用命令大全
    项目维护环境部署
    bootstrap-table
    bootstrap-datetimepicker
  • 原文地址:https://www.cnblogs.com/zhshlimi/p/10792591.html
Copyright © 2020-2023  润新知