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; } } }