SpringBoot Redisロック、データベースロック、パフォーマンスとの比較

4251 ワード

一、比較
パフォーマンス:DBロック>Redisロック
実現難易度:DBロック
フレキシブルアプリケーション: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 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バージョンなどもあります.多くの細部は言わないで....みんな興味があってゆっくり研究~~~~