歡迎您光臨本站 註冊首頁

· redis setnx雜誌閱讀

Redis的SETNX的使用詳解

admin @ 2020-04-20 reply:0

一.介紹

在 Redis 裡,所謂 SETNX,是「SET if Not eXists」的縮寫,也就是隻有不存在的時候才設定,可以利用它來實現鎖的效果。
SETNX key value

將 key 的值設為 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則 SETNX 不做任何動作。
二.選項命令

在SET命令中,有很多選項可用來修改命令的行為。 以下是SET命令可用選項的基本語法。

    redis 127.0.0.1:6379> SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]

(1)設定指定的到期時間(以秒為單位)。

    ShellEX seconds −

(2)設定指定的到期時間(以毫秒為單位)

    PX milliseconds

(3)僅在鍵不存在時設定鍵

    NX

(4)只有在鍵已存在時才設定

    XX

示例

    redis 127.0.0.1:6379> SET mykey “redis” EX 60 NX
    OK

Shell以上示例將在鍵“mykey”不存在時,設定鍵的值,到期時間為60秒。
三.使用redisTemplate操作SetNx
1.設定setNx

  /**
     * @Author lss0555
     * @Description  setNx操作  
     **/
    @Override
    public boolean setNx(String key,String value, long time) {
        try {
            RedisCallback<String> callback = (connection) -> {
                JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                return commands.set(key, value, "NX", "PX", time);
            };
            String result = redisTemplate.execute(callback);

            return !StringUtils.isEmpty(result);
        } catch (Exception e) {
            logger.error("set redis occured an exception", e);
        }
        return false;
    }

   

2.獲取getNx

/**
     * @Description  getNx
     **/
    @Override
    public String getNx(String key) {
        try {
            RedisCallback<String> callback = (connection) -> {
                JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                return commands.get(key);
            };
            String result = redisTemplate.execute(callback);
            return result;
        } catch (Exception e) {
            logger.error("get redis occured an exception", e);
        }
        return "";
    }


3.lua指令碼刪除redis中匹配value的key

在分散式鎖的應用中,使用lua指令碼刪除redis中匹配value的key,可以避免由於方法執行時間過長而redis鎖自動過期失效的時候誤刪其他執行緒的鎖,spring自帶的執行指令碼方法中,叢集模式直接丟擲不支援執行指令碼的異常,所以只能拿到原redis的connection來執行指令碼。

1.使用指令碼的好處
(1)減少網路開銷,在Lua指令碼中可以把多個命令放在同一個指令碼中執行
(2)原子操作,redis會將整個指令碼作為一個整體執行,中間不會被其他命令插入。
(3)複用性,客戶端傳送的指令碼會永遠儲存在redis中,這意味著其他客戶端可以複用這一指令碼來完成同樣的邏輯

2.使用示例

@Override
    public boolean unlcok(String key,String value) {
        try {
            List<String> keys = new ArrayList<>();
            keys.add(key);
            List<String> args = new ArrayList<>();
            args.add(value);          
            RedisCallback<Long> callback = (connection) -> {
                Object nativeConnection = connection.getNativeConnection();
                // 叢集模式和單機模式雖然執行指令碼的方法一樣,但是沒有共同的介面,所以只能分開執行
                // 叢集模式
                if (nativeConnection instanceof JedisCluster) {
                    return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }

                // 單機模式
                else if (nativeConnection instanceof Jedis) {
                    return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }
                return 0L;
            };
            Long result = redisTemplate.execute(callback);
            return result != null && result > 0;
        } catch (Exception e) {
            logger.error("release lock occured an exception", e);
        } finally {
            // 清除掉ThreadLocal中的資料,避免記憶體溢位
            //lockFlag.remove();
        }
        return false;
    }
    
    public static final String UNLOCK_LUA;    
    static {
        StringBuilder sb = new StringBuilder();
        sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
        sb.append("then ");
        sb.append("    return redis.call(\"del\",KEYS[1]) ");
        sb.append("else ");
        sb.append("    return 0 ");
        sb.append("end ");
        UNLOCK_LUA = sb.toString();
    }

[admin via ] Redis的SETNX的使用詳解已經有410次圍觀

http://coctec.com/magazine/show-post-item-103.html