stringRedisTemplate.setIfAbsent (해결 레디 스 물건을 사용) 및 발생 만료 시간 문제 설정

봄 최신 레디 스 버전 : 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. 버전 2.1 이상으로 업그레이드 레디 스, 다음 사용

이미지 캡션
setIfAbsent에서 직접 만료 시간을 설정

업데이트 : 
직접 멀티에서 API 광고 ()와 간부 (), 그래서 멀티 ()와 간부 () 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