redis分布式锁实现

本文介绍了一种使用Redis实现分布式锁的算法,通过setIfAbsent确保锁的唯一性,并利用getAndSet实现锁的续期与释放,有效防止了死锁的发生。

 /**
     * 加锁
     */
    public boolean lock(String key, String value) {
        //setIfAbsent相当于jedis中的setnx,如果能赋值就返回true,如果已经有值了,就返回false
        //即:在判断这个key是不是第一次进入这个方法
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
            //第一次,即:这个key还没有被赋值的时候
            return true;
        }
        String current_value = redisTemplate.opsForValue().get(key);
        if (!MyStringUtils.Object2String(current_value).equals("")
                //超时了
                && Long.parseLong(current_value) < System.currentTimeMillis()) {//①
            String old_value = redisTemplate.opsForValue().getAndSet(key, value);//②
            if (!MyStringUtils.Object2String(old_value).equals("")
                    && old_value.equals(current_value)) {
                return true;
            }
        }
        return false;
    }

    //解锁
    public void unlock(String key, String value) {
        try {
            if (MyStringUtils.Object2String(redisTemplate.opsForValue().get(key)).equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

Redis 分布式锁实现方法有多种,以下是一些常见方案: ### SETNX + EXPIRE 方案 使用 `SETNX` 命令尝试获取锁,若返回 `1` 表示获取成功,接着使用 `EXPIRE` 命令为锁设置过期时间,防止死锁。 ```python import redis redis_client = redis.Redis(host='localhost', port=6379, db=0) redis_key = "redis_key_001" get_lock = redis_client.setnx(redis_key, "极简版redis锁") if get_lock: redis_client.expire(redis_key, 10) # 设置 10 秒过期时间 print("获取到redis锁") # 业务逻辑 redis_client.delete(redis_key) else: print("未获取到redis锁") ``` ### SET 的扩展命令(SET EX PX NX)方案 使用 `SET` 命令的扩展参数,原子性地完成设置键值和过期时间,避免 `SETNX` 和 `EXPIRE` 非原子操作的问题。 ```python import redis redis_client = redis.Redis(host='localhost', port=6379, db=0) redis_key = "redis_key_001" get_lock = redis_client.set(redis_key, "极简版redis锁", ex=10, nx=True) if get_lock: print("获取到redis锁") # 业务逻辑 redis_client.delete(redis_key) else: print("未获取到redis锁") ``` ### 使用 Lua 脚本(包含 SETNX + EXPIRE 两条指令)方案 通过 Lua 脚本保证 `SETNX` 和 `EXPIRE` 操作的原子性。 ```python import redis redis_client = redis.Redis(host='localhost', port=6379, db=0) redis_key = "redis_key_001" lua_script = """ if redis.call('SETNX', KEYS[1], ARGV[1]) == 1 then redis.call('EXPIRE', KEYS[1], tonumber(ARGV[2])) return 1 else return 0 end """ get_lock = redis_client.eval(lua_script, 1, redis_key, "极简版redis锁", 10) if get_lock: print("获取到redis锁") # 业务逻辑 redis_client.delete(redis_key) else: print("未获取到redis锁") ``` ### SET EX PX NX + 校验唯一随机值,再释放锁方案 在加锁时设置唯一随机值,释放锁时先校验该值,避免误解锁。 ```python import redis import uuid redis_client = redis.Redis(host='localhost', port=6379, db=0) redis_key = "redis_key_001" unique_value = str(uuid.uuid4()) get_lock = redis_client.set(redis_key, unique_value, ex=10, nx=True) if get_lock: print("获取到redis锁") # 业务逻辑 lua_script = """ if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end """ release_result = redis_client.eval(lua_script, 1, redis_key, unique_value) if release_result: print("释放锁成功") else: print("释放锁失败") else: print("未获取到redis锁") ``` ### 开源框架 Redisson 方案 Redisson 是一个基于 Redis 实现的分布式和可扩展的 Java 数据结构集合,提供了简单易用的分布式锁实现。 ```java import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class RedissonLockExample { public static void main(String[] args) { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); RLock lock = redisson.getLock("redis_key_001"); try { lock.lock(); System.out.println("获取到redis锁"); // 业务逻辑 } finally { lock.unlock(); System.out.println("释放锁成功"); } } } ``` ### 多机实现分布式锁 Redlock 方案 在多个 Redis 节点上获取锁,只有在大多数节点上都成功获取到锁,才认为加锁成功。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值