如何利用redis 實現分佈式項目枷鎖功能

分佈式項目,由於用戶需要佔座需求,防止用戶同時進入該鏈接,導致事務失效,單獨使用事務的話,項目在兩臺服務器上面,導致事務實現不了這種鎖,因此添加上了redis單線程鎖。

具體實現流程 redis 工具類方法

    // 鎖名稱
    public static final String LOCK_PREFIX = "redis_lock";
    // 加鎖失效時間,毫秒
    public static final int LOCK_EXPIRE = 10000; // ms

/**
     * 最終加強分佈式鎖
     *
     * @param key
     *            key值
     * @return 是否獲取到
     */
    public boolean lock(String key) {
        String lock = LOCK_PREFIX + key;
        // 利用lambda表達式
        return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
            long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
            log.info("失效的時間是【{}】",String.valueOf(expireAt));
            Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
            
            log.info("查看acquire========"+acquire);
            if (acquire) {
                return true;
            } else {
                byte[] value = connection.get(lock.getBytes());
                
                log.info("查看value========"+value);
                if (Objects.nonNull(value) && value.length > 0) {
                    long expireTime = Long.parseLong(new String(value));
                    log.info("查看expireTime========"+expireTime);
                    // 如果鎖已經過期
                    if (expireTime < System.currentTimeMillis()) {
                        log.info("如果鎖已經過期,重新加鎖");
                        // 重新加鎖,防止死鎖
                        byte[] oldValue = connection.getSet(lock.getBytes(),
                                String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
                        log.info("查看oldValue========"+oldValue);
                        
                        
                        Boolean  newLoing= Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
                        log.info("查看Long.parseLong========"+newLoing);
                        return newLoing;
                    }
                }
            }
            return false;
        });
    }
    /**
     * 刪除鎖
     *
     * @param key
     */
    public void deleteLock(String key) {
        redisTemplate.delete(key);
    }
    

 

調用工具方法

@Override
    public Boolean testRedis(String code) {
        System.out.println("測試分佈式鎖的應用說明============查看鎖狀態"+redisManager.exists("redis_lockbbbbbbbbbb"));
        Boolean flag=true;
        System.out.println("測試分佈式鎖的應用說明============查看continue之後是否執行此日誌");
        try {
            while (true) {
                if(redisManager.lock("bbbbbbbbbb")) {
                    Thread.sleep(5000);
                    code.substring(0, 2);
                    System.out.println("測試分佈式鎖的應用說明=============這是被鎖住的進程"+code);
                    System.out.println("測試分佈式鎖的應用說明=============查看是否進行下面邏輯"+code);
                    redisManager.deleteLock("redis_lockbbbbbbbbbb");
                    return true;
                }else {
                    Thread.sleep(1000);
                    System.out.println("測試分佈式鎖的應用說明=============這是等待進行釋放鎖");
                    continue;
                }
            }
        } catch (Exception e) {
            System.out.println("測試分佈式鎖的應用說明=============拋出異常後發音日誌");
            e.printStackTrace();
            
        }
        System.out.println("測試分佈式鎖的應用說明=============跳出循環後執行這個方法這是直接返回數據");
        return false;
    
    }
這是整個過程的使用,具體實現邏輯:

當用戶進入的時候,根據規則生成redis 的key ,同時添加過時時間,如果兩個人同時進入,那麼第一次進入的人的redis是開鎖狀態,第二個人進入的時候是閉鎖狀態, 因此第一個人會在serviceimpl中執行 Thread.sleep(5000);方法,相當於具體的邏輯,當邏輯執行完之後,將鎖釋放掉,第二個用戶會一直走下面的循環,直到鎖開了之後纔會進入具體的邏輯,

工具類中的邏輯  針對上鎖時間而言,並不是在超時之後就將redis 清空,工具的邏輯爲當超過過期時間之後,會再次給redis的key加鎖,這樣第二個請求就會進入,當然這樣的問題就是當第一個沒有執行完沒有自動釋放鎖的時候,鎖自動又加上了, 第二個請求會直接進入,因此枷鎖的時間需要想好,儘量在一個請求可以執行完的情況下的時間的幾倍。當然所有的邏輯中的要加上try catch 如果邏輯出錯,需要在catch中將鎖解開。大致就是這個意思!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章