😭
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
사랑해요 진짜 오늘 4시간정도 이거만 했는데