stringRedisTemplate.setIfAbsent(解決Redisのものを使用)と遭遇した有効期限の問題を設定します

春-日付Redisのバージョン:1.6.2
シナリオ:使用の際にはsetIfAbsent(key,value)、希望が必要に使用する一方で、キーの有効期限を設定するにはsetIfAbsent、指定された値の後に戻るには、プロセスを、その次のコードを使用します。

boolean store = stringRedisTemplate.opsForValue().setIfAbsent(key,value);
if(store){
  stringRedisTemplate.expire(key,timeout); 
  // todo something...  
}

このコードには問題がある:首尾よく切断さsetIfAbsentすると、次のコードは、有効期限を設定することstringRedisTemplate.expire(key,timeout); が強制され、この時間は、データベースの多くは何の有効期限データを存在しないがあるでしょう。方法を考え、次のように改訂されたコードは、トランザクション管理を追加することです。

stringRedisTemplate.setEnableTransactionSupport(true);
stringRedisTemplate.multi();
boolean store = stringRedisTemplate.opsForValue().setIfAbsent(key,value);
if(store){
  stringRedisTemplate.expire(key,timeout);   
}
stringRedisTemplate.exec();
if(store){
    // todo something... }

これは、プロセス全体の一貫性を保証します。このことはできますが、私は、ドキュメントに次のを発見したので、実際には、常に満足できるものではない理由は次のとおりです。
画像のキャプション

トランザクション管理を添加した後、setIfAbsent戻り値はnullであることが判明したので、さらに後に判別する方法はありません。

まあ、アドレスに進みます。

stringRedisTemplate.setEnableTransactionSupport(true);
stringRedisTemplate.multi();
String result = stringRedisTemplate.opsForValue().get(key);
if(StringUtils.isNotBlank(result)){
    return false;
}
// 锁的过期时间为1小时 stringRedisTemplate.opsForValue().set(key, value,timeout); stringRedisTemplate.exec(); // todo something...

上記のコードが、それはまだ問題がある、同時に発生した場合、String result = stringRedisTemplate.opsForValue().get(key); その後、同時に汚れたデータを書き込む、空のキーを取得するには、同時に複数のスレッドが存在します。


最終的な解決策:

  1. 使用stringRedisTemplate.exec();setIfAbsent成功するかどうかを判断するために、戻り値を
stringRedisTemplate.setEnableTransactionSupport(true);
stringRedisTemplate.multi();
stringRedisTemplate.opsForValue().setIfAbsent(lockKey,JSON.toJSONString(event));
stringRedisTemplate.expire(lockKey,Constants.REDIS_KEY_EXPIRE_SECOND_1_HOUR, TimeUnit.SECONDS);
List result = stringRedisTemplate.exec(); // 这里result会返回事务内每一个操作的结果,如果setIfAbsent操作失败后,result[0]会为false。
if(true == result[0]){ // todo something... }
  1. Redisの使用、その後、バージョン2.1以降にアップグレード

画像のキャプション
setIfAbsentで直接有効期限を設定します

更新: 
あなたはRedisのトランザクションを使用すると、デッドロックにつながる接続するJavaを使用していないとき、次のように直接マルチ()内のAPIを使用するとexec()することはできませんので、マルチ()とexec()stringRedisTemplateは二回、正しい方法は次のとおりです。

    private Boolean setLock(RecordEventModel event) {
        String lockKey = event.getModel() + ":" + event.getAction() + ":" + event.getId() + ":" + event.getMessage_id(); log.info("lockKey : {}" , lockKey); SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() { List<Object> exec = null; @Override @SuppressWarnings("unchecked") public Boolean execute(RedisOperations operations) throws DataAccessException { operations.multi(); stringRedisTemplate.opsForValue().setIfAbsent(lockKey,JSON.toJSONString(event)); stringRedisTemplate.expire(lockKey,Constants.REDIS_KEY_EXPIRE_SECOND_1_HOUR, TimeUnit.SECONDS); exec = operations.exec(); if(exec.size() > 0) { return (Boolean) exec.get(0); } return false; } }; return stringRedisTemplate.execute(sessionCallback); }

 

おすすめ

転載: www.cnblogs.com/exmyth/p/11324777.html