参考:https://redis.io/commands/set
基于Redis命令:SET key valueNX EX max-lock-time
适用于redis单机和redis集群模式
1.SET命令是原子性操作,NX指令保证只要当key不存在时才会设置value
2.设置的value要有唯一性,来确保锁不会被误删(value=系统时间戳+UUID)
3.当上述命令执行返回OK时,客户端获取锁成功,否则失败
3.客户端可以通过redis释放脚本来释放锁
4.如果锁到达了最大生存时间将会自动释放
只有当前key的value和传入的value相同才会执行DEL命令
import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.StringRedisTemplate; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * redis锁工具类 */ public class RedisLock { public static final String OK = "OK"; public static final String UNLOCK_LUA = "if redis.call(\"get\",KEYS[1]) == ARGV[1] " + "then " + " return redis.call(\"del\",KEYS[1]) " + "else " + " return 0 " + "end "; /** * 单机和集群redis分布式锁 * * 参考:https://redis.io/commands/set * * 版本:Redis Version >= 2.6.12 * * 命令:SET key-name uuid NX EX max-lock-time * * @param keyName redis key name * @param stringRedisTemplate stringRedisTemplate * @param expireSeconds 锁定的最大时长 * @return 锁定结果 */ public static LockRes tryLock(String keyName, StringRedisTemplate stringRedisTemplate, Integer expireSeconds) { // 将value设置为当前时间戳+随机数 String lockValue = System.currentTimeMillis() + UUID.randomUUID().toString(); String redisLockResult = stringRedisTemplate.execute((RedisCallback<String>) connection -> { Object nativeConnection = connection.getNativeConnection(); String result = null; // 集群 if (nativeConnection instanceof JedisCluster) { result = ((JedisCluster) nativeConnection).set(keyName, lockValue, "NX", "EX", expireSeconds); } // 单机 if (nativeConnection instanceof Jedis) { result = ((Jedis) nativeConnection).set(keyName, lockValue, "NX", "EX", expireSeconds); } return result; }); if (OK.equalsIgnoreCase(redisLockResult)) { return new LockRes(true, keyName, lockValue); } else { return new LockRes(false, keyName, null); } } public static Boolean unlock(LockRes lockRes, StringRedisTemplate stringRedisTemplate) { if (lockRes.isFlag()) { return stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> { Object nativeConnection = connection.getNativeConnection(); Long result = 0L; List<String> keys = new ArrayList<>(); keys.add(lockRes.getKey()); List<String> values = new ArrayList<>(); values.add(lockRes.getValue()); // 集群 if (nativeConnection instanceof JedisCluster) { result = (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, values); } // 单机 if (nativeConnection instanceof Jedis) { result = (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, values); } return result == 1L; }); } else { return true; } } }