天天看點

jedis setnx實作鎖機制

線上接口有同使用者請求的并發問題,是以準備用setnx做一個鎖

為什麼要用setnx:因為 Redis Setnx(SET if Not eXists) 指令是在指定的 key 不存在時,為 key 設定指定的值,是以setnx是redis的一個原子性指令

實作思路:根據使用者資訊生成一個key,放緩存待 接口執行完畢之後,删除該緩存,下次同使用者請求進來,如果未執行完畢則緩存還存在,放緩存失敗則傳回對應提示資訊,接口停止繼續執行

上代碼:

@Autowired(required = false)
    private Pool<Jedis> poolJedis;


   /**
     * 添加鎖 防并發 此方法添加鎖未設定過期時間,需手動釋放
     *
     * @param key key
     * @param seconds 緩存過期時間
     * @return boolean
     */
    public boolean tryLock(String key,int seconds) {
        if (Validator.isNullOrEmpty(poolJedis)) {
            return false;
        }
        try (Jedis jedisCluster = poolJedis.getResource()) {
            // 在指定的 key 不存在時,為 key 設定指定的值。
            // 根據以下第三個nxxx參數,把key、value set到redis中
            // NX : not exists, 隻有key 不存在時才把key value set 到redis
            // XX : is  exists, 隻有key 存在時才把key value set 到redis
            // 第四個expx參數有兩個值可選 :
            // EX : seconds 秒
            // PX :  milliseconds 毫秒
            String nx = jedisCluster.set(key, "value", "NX", "EX", seconds);
            if (Validator.isNotNullOrEmpty(nx) && "OK".equals(nx)) {
                return true;
            }
        } catch (Exception e) {
            LOGGER.error("addLock error:", e);
        }
        return false;
    }



   /**
     * 釋放鎖
     *
     * @param key key
     */
    public void clearLock(String key) {
        Jedis jedisCluster = null;
        try {
            jedisCluster = pool.getResource();
            Long a = jedisCluster .del(key);
        } catch (Exception e) {
            LOGGER.error("", e);
            //線程休眠1秒
            try {
                Thread.sleep(1000);
                removeLock(key);
            } catch (InterruptedException e1) {
                LOGGER.error("removeLock error:", e1);
                Thread.currentThread().interrupt();
            } finally {
                if (jedisCluster != null) {
                    jedisCluster .close();
                }
            }
        }
    }
           

繼續閱讀