【转】Redis分布式锁 SET命令实现

参考: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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值