Redisson分布式锁使用

一、使用 RedisTemplate 操作分布式锁

原子加锁(uuid Value+过期时间)+原子解锁(lua脚本)+加长过期时间

  • UUID :让锁区分,防止错删其他锁
  • 设置锁过期时间:当业务异常导致无法释放锁形成锁死,设置过期时间自动释放锁
  • Lua脚本:能够保证删除操作的原子性
  • 加长过期时间:过期时间必须大于业务执行时间
	1.加锁 (set key)
	try{
		2.业务:向redis缓存存入数据
		(1)查redis缓存数据,缓存有直接返回,(2)缓存没查到直接查数据库,(3)在锁释放之前 放入redis缓存
	}
	catch{
		处理异常
	}
	finally{
		3.释放锁 (delete key)
	}
	
public Map<String, List<CategoryLevel2Vo>> getCatelogJsonFromDataWithRedisLock() {

        //set NX key不存在才能set
        //设置set lock hah EX 300 NX,设置过期时间EX,防止死锁,加锁跟设置过期时间必须是原子性操作
        String uuid = UUID.randomUUID().toString();
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid,300,TimeUnit.SECONDS);
        //lock为true set成功
        if (lock){
            System.out.println("获取分布式锁成功");
            //加锁成功
            Map<String, List<CategoryLevel2Vo>> dataFromDb;
            try {
                dataFromDb = getDataFromDb();
            } finally {
                //释放锁(删除lock)
                //使用lua删除锁脚本,或者值+比较值+删除锁(脚本可以保证原子性)
                String redisScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
                Long execute = stringRedisTemplate.execute(new DefaultRedisScript<Long>(redisScript, Long.class), Arrays.asList("lock"), uuid);
            }
            return dataFromDb;
        }else {
            //加锁失败
            System.out.println("获取分布式锁失败,等待重试");
            //休眠
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //自旋
            return getCatelogJsonFromDataWithRedisLock();
        }

二、Lock锁

为什么Lock锁不用循环判断是否拿到锁?
lock是阻塞锁,拿不到锁不会执行
Lock锁与RedisTemplate 操作分布式锁区别,Redisson与Redis锁的区别?

  • 自动续期,lock.lock()加锁时,看门狗LockWatchdogTimeout定时更新过期时间
  • 防止死锁,当业务异常导致无法释放锁,看门狗默认30s释放锁
1.加锁 lock.lock() 或 lock.lock(10, TimeUnit.SECONDS);
try{
	2.业务...
}catch{
	处理异常
}finally{
	3.释放锁 lock.unlock();
}

1.lock.lock(); 有续期
如果业务未完成,则锁自动续期,看门狗LockWatchdogTimeout默认时间30s,续期按
如果业务完成,则不会续期,如果不手动释放锁,默认30s后释放
如果占锁,则开启定时任务,重新设置过期时间(LockWatchdogTimeout),定时任务:使用掉三分之一的LockWatchdogTimeout就恢复成 30s

2.lock.lock(10, TimeUnit.SECONDS); 无续期,推荐使用
注意:设置锁时间必须大于业务执行时间,否则业务结束之前释放锁会被其他线程占锁,当业务结束释放时,删除了其他线程的锁
没有看门狗LockWatchdogTimeout
锁时间结束不会自动续期,设置锁时间大于业务执行时间

占锁成功,如果出现事故导致无法释放锁,在不抛出异常的情况下,会默认30s后释放锁,所以不会存在死锁的问题
在这里插入图片描述
锁的名字,粒度越细越好 product-11-lock、product-12-lock

public Map<String, List<CategoryLevel2Vo>> getCatelogJsonFromRedissonLock() {
        //锁的名字,粒度越细越好  product-11-lock、product-12-lock
        RLock lock = redissonClient.getLock("CatelogJson-lock");
        //加锁成功
        lock.lock();
        Map<String, List<CategoryLevel2Vo>> dataFromDb = null;
        try {
            dataFromDb = getDataFromDb();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁
            lock.unlock();
        }
        return dataFromDb;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值