Redis分布式锁

Redis 分布式锁|从青铜到钻石的五种演进方案:https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&mid=2451954663&idx=1&sn=4bd071b6aaede114263f88c790b61371&chksm=8d1c2278ba6bab6eca2ef44f21b2178cc719fffe124289b68128c0dad72429fe5f286854157a&scene=21#wechat_redirect

// 1.生成唯一 id
String uuid = UUID.randomUUID().toString();
// 2. 抢占锁
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
if(lock) {
    System.out.println("抢占成功:" + uuid);
    // 3.抢占成功,执行业务
    List<TypeEntity> typeEntityListFromDb = getDataFromDB();
    // 4.获取当前锁的值
    String lockValue = redisTemplate.opsForValue().get("lock");
    // 5.如果锁的值和设置的值相等,则清理自己的锁
    if(uuid.equals(lockValue)) {
        System.out.println("清理锁:" + lockValue);
        redisTemplate.delete("lock");
    }
    return typeEntityListFromDb;
} else {
    System.out.println("抢占失败,等待锁释放");
    // 4.休眠一段时间
    sleep(100);
    // 5.抢占失败,等待锁释放
    return getTypeEntityListByRedisDistributedLock();
}

1.生成随机唯一 id,给锁加上唯一值。
2.抢占锁,并设置过期时间为 10 s,且锁具有随机唯一 id。
3.抢占成功,执行业务。
4.执行完业务后,获取当前锁的值。
5.如果锁的值和设置的值相等,则清理自己的锁。

上面的方案看似很完美,但还是存在问题:第 4 步和第 5 步并不是原子性的。

写到Lua脚本中,原子性执行。
那如何用脚本进行删除呢?

我们先来看一下这段 Redis 专属Lua脚本:

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

那么这段脚本怎么在 Java 项目中执行呢?

分两步:先定义脚本;用 redisTemplate.execute 方法执行脚本。

// 脚本解锁
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid);

上面的代码中,KEYS[1] 对应“lock”,ARGV[1] 对应 “uuid”,含义就是如果 lock 的 value 等于 uuid 则删除 lock。

而这段 Redis 脚本是由 Redis 内嵌的 Lua 环境执行的,所以又称作 Lua 脚本。

// 1.生成唯一 id
String uuid = UUID.randomUUID().toString();
// 2. 抢占锁
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
if(lock) {
    System.out.println("抢占成功:" + uuid);
    // 3.抢占成功,执行业务
    List<TypeEntity> typeEntityListFromDb = getDataFromDB();
    // 4,5步结合到一起脚本解锁
	String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
	redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid);
    return typeEntityListFromDb;
} else {
    System.out.println("抢占失败,等待锁释放");
    // 4.休眠一段时间
    sleep(100);
    // 5.抢占失败,等待锁释放
    return getTypeEntityListByRedisDistributedLock();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值