spring RedisTemplate.hasKey()값이 null이 나올 경우

greenTea·2023년 9월 10일
0

spring RedisTemplate.hasKey()값이 null이 나올 경우

😭redis를 캐시로 이용하여 사용하고 있는 상황인데 아래와 같은 코드를 사용하면 해당 결과값이 null이 나오는 상황이 발생하였습니다.

Config

@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

profile
greenTea입니다.

0개의 댓글