😭
redis
를 캐시로 이용하여 사용하고 있는 상황인데 아래와 같은 코드를 사용하면 해당 결과값이null
이 나오는 상황이 발생하였습니다.
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.data.redis.database}")
private int database;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(host, port);
lettuceConnectionFactory.setDatabase(database);
return lettuceConnectionFactory;
}
@Bean
public RedisTemplate<String,Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setEnableTransactionSupport(true);
return redisTemplate;
}
}
🧐host,port,database를 설정파일에서 가져와 사용하고 있으며 직렬화의 경우 위와 같이 사용하였습니다. 또한 트랜잭션과 같이 움직일 수 있게
setEnableTransactionSupport(true)
를 설정해주었습니다.다음은 문제가 발생한 코드입니다.
public String requestShortUrl(String shortUrl) {
if (redisTemplate.hasKey(shortUrl)) {
return (String) redisTemplate.opsForValue().get(shortUrl);
}
Optional<ShortUrl> byShortedUrl = urlRepository.findByShortedUrl(shortUrl);
if (byShortedUrl.isPresent()) {
ShortUrl shortResult = byShortedUrl.get();
redisTemplate.opsForValue().set(shortResult.getShortedUrl(),shortResult.getOriginalUrl(),3,TimeUnit.DAYS);
return byShortedUrl.get().getOriginalUrl();
}
throw new NoSuchUrlException();
}
😰다른 로직은 제쳐두고 가장 위의
hasKey(shortUrl)
을 사용하면 결과과null
이 나오면서nullpointerexception
가 발생하게 되었습니다.문제가 발생할 수 있는 이유로는 처음에는 넘겨준 값이
null
인 줄 알았으나 디버그로 확인 결과 제대로 넘어가는 것을 확인하였습니다.그래서 구글링을 통해서 해당 문제의 원인을 찾았습니다.
Stack Over Flow - Redis hasKey method return NULL에 따르면
null
이 나올수 있는 경우로는 3가지가 있는데1. key가 존재하지 않는다.
2. pipline 사용 중인 상태이다.
3. 트랜잭션이 걸려있는 상태이다.🧐
null
이 나오는 이유로는파이프라인
이나트랜잭션
내에서Redis
명령을 실행하면, 명령의 결과가 즉시 반환되지 않고 커맨드 버퍼에 저장되는데 해당 값은트랜잭션
이 커밋되거나 롤백이 되야 해당 값이 반환되는데트랜잭션
이 진행중인 상태에서는 해당 값이 아직 버퍼에 남아 있는 상태로 아직 아무 결과값이 없는 상태입니다. 그래서트랜잭션
이 끝나기전에 부르게 되면null
이 나오게 되는 것입니다.<파이프 라인이란?>
Redis 명령어를 한 번에 보내고 한 번에 처리하는 기술입니다.🥳
redisTemplate.setEnableTransactionSupport(true); -> 제거 또는 false 설정
위에서 보셨다면 아시겠지만 제가 설정파일에서 트랜잭션에 같이 참여하도록 하였는데 해당 값을 주석처리하고 진행한 결과 값이 제대로 나오는 것을 확인 할 수 있었습니다.
출처 : Stack Over Flow - Redis hasKey method return NULL
참고자료: spring - redisTemplate