SpringBoot Redis锁,数据库锁,实现与性能比较

一、比较

性能:DB锁>Redis锁

实现难度:DB锁<Redis锁

灵活应用:Redis锁>DB锁

业务复杂度:DB锁>Redis锁

 

二、实现

  1、DB锁

   db锁的实现比较简单,通过 select * from table where id=? for update 进行行级锁。

直接上代码

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)//一定要开启事务,才能用锁哦!!!
    public Do lockDbTest(Long id) {
        Do do=DoDao.lockById(id);
        //业务实现.....
        
        return do;
    }

2、Redis锁

redis锁实现思路:原子性操作redis。并且加上过期时间,避免服务器崩溃等原因,造成死锁。

代码:

    public boolean tryLock(RedisLock redisLock) {
        int i = 0;
        while (i < 3) {
            if (stringRedisTemplate.opsForValue().setIfAbsent(redisLock.getLockKey(), redisLock.getLockValue(), 30, TimeUnit.SECONDS)) {
//                System.out.println(Thread.currentThread().getId() + "加锁成功! key:"+redisLock.getLockKey()+"value:"+redisLock.getLockValue());
                //开启定时刷新过期时间
                redisLock.isOpenExpirationRenewal = true;
                redisLock.scheduleExpirationRenewal(stringRedisTemplate);
                return true;
            }
            i++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        System.out.println(Thread.currentThread().getId() + "加锁失败!");
        return false;
    }

由于有了过期时间,所以要加上刷新过期时间控制。

代码:

    public RedisLock(String lockKey) {
        this.lockKey = lockKey;
        this.lockValue = UUID.randomUUID().toString();
    }

    private String lockKey;
    private String lockValue;
    protected volatile boolean isOpenExpirationRenewal = true;

    private StringRedisTemplate stringRedisTemplate;

    public String getLockKey() {
        return lockKey;
    }


    public String getLockValue() {
        return lockValue;
    }

    public void setLockValue(String lockValue) {
        this.lockValue = lockValue;
    }

    /**
     * 开启定时刷新
     */
    protected void scheduleExpirationRenewal(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
        Thread renewalThread = new Thread(new ExpirationRenewal());
        renewalThread.start();
    }


    public void sleepBySencond(int sencond) {
        try {
            Thread.sleep(sencond * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刷新key的过期时间
     */
    private class ExpirationRenewal implements Runnable {
        @Override
        public void run() {
            while (isOpenExpirationRenewal) {
                //休眠10秒
                System.out.println("执行延迟失效时间中..."+Thread.currentThread().getId());
                stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS);
                sleepBySencond(10);
            }
        }
    }

最后来一个释放锁

直接代码上:

    public boolean releaseLock(RedisLock redisLock) {
//     错误示范哦   stringRedisTemplate.delete(redisLock.getLockKey());
//        redisLock.isOpenExpirationRenewal = false;
        redisLock.isOpenExpirationRenewal = false;
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(RELEASE_LOCK_LUA_SCRIPT);
        redisScript.setResultType(Long.class);

        Long result=stringRedisTemplate.execute(redisScript, Collections.singletonList(redisLock.getLockKey()), redisLock.getLockValue());
        if(result==RELEASE_LOCK_SUCCESS_RESULT) {
//            System.out.println("解锁成功:key:"+redisLock.getLockKey()+"value:"+redisLock.getLockValue());
            return true;
        }
//        System.out.println("失败解锁结果:key:"+redisLock.getLockKey()+"value:"+redisLock.getLockValue());
//        System.out.println("失败解锁锁值:"+stringRedisTemplate.opsForValue().get(redisLock.getLockKey()));
        return false;
    }

需要解释一下的是,redisLock既然有key了,为啥还要value呢,这是由于避免非本客户端来解锁哦。

其中还有需要注意的spring-boot版本呀等问题。很多细节就不说了....大家有兴趣慢慢研究~~~~~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值