基于redisTemplate的redis的分布式锁正确打开方式

匿名 (未验证) 提交于 2019-12-03 00:44:02

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisCommands;  import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.UUID;  /**  * @author superchen  * @since 2018/5/16  **/ @Component public class RedisDistributedLock{      @Resource     private RedisTemplate<String, Object> redisTemplate;      public static final String UNLOCK_LUA;      static {         StringBuilder sb = new StringBuilder();         sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");         sb.append("then ");         sb.append("    return redis.call(\"del\",KEYS[1]) ");         sb.append("else ");         sb.append("    return 0 ");         sb.append("end ");         UNLOCK_LUA = sb.toString();     }      private final Logger logger = LoggerFactory.getLogger(RedisDistributedLock.class);      public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {         boolean result = setRedis(key, expire);         // 如果获取锁失败,按照传入的重试次数进行重试         while ((!result) && retryTimes-- > 0) {             try {                 logger.debug("lock failed, retrying..." + retryTimes);                 Thread.sleep(sleepMillis);             } catch (InterruptedException e) {                 return false;             }             result = setRedis(key, expire);         }         return result;     }      public boolean setRedis(String key, long expire) {         try {             RedisCallback<String> callback = (connection) -> {                 JedisCommands commands = (JedisCommands) connection.getNativeConnection();                 String uuid = UUID.randomUUID().toString();                 return commands.set(key, uuid, "NX", "PX", expire);             };             String result = redisTemplate.execute(callback);              return !StringUtils.isEmpty(result);         } catch (Exception e) {             logger.error("set redis occured an exception", e);         }         return false;     }      public String get(String key) {         try {             RedisCallback<String> callback = (connection) -> {                 JedisCommands commands = (JedisCommands) connection.getNativeConnection();                 return commands.get(key);             };             String result = redisTemplate.execute(callback);             return result;         } catch (Exception e) {             logger.error("get redis occured an exception", e);         }         return "";     }      public boolean releaseLock(String key,String requestId) {         // 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除         try {             List<String> keys = new ArrayList<>();             keys.add(key);             List<String> args = new ArrayList<>();             args.add(requestId);              // 使用lua脚本删除redis中匹配value的key,可以避免由于方法执行时间过长而redis锁自动过期失效的时候误删其他线程的锁             // spring自带的执行脚本方法中,集群模式直接抛出不支持执行脚本的异常,所以只能拿到原redis的connection来执行脚本             RedisCallback<Long> callback = (connection) -> {                 Object nativeConnection = connection.getNativeConnection();                 // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行                 // 集群模式                 if (nativeConnection instanceof JedisCluster) {                     return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);                 }                  // 单机模式                 else if (nativeConnection instanceof Jedis) {                     return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);                 }                 return 0L;             };             Long result = redisTemplate.execute(callback);              return result != null && result > 0;         } catch (Exception e) {             logger.error("release lock occured an exception", e);         } finally {             // 清除掉ThreadLocal中的数据,避免内存溢出             //lockFlag.remove();         }         return false;     }  } 

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