Redis
먼저 결과 코드를 쓰자면 이거다.
public StatDictResponseDto getDto(String key){
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
Dto data = redis.get(key);
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
return data;
}
이틀동안 붙잡고 있던 문제였다. 단순하지 않은 구조의(내부에 List<>를 가지고 있는 형태의) DTO를 Redis로 불러오려고 하니 정상적으로 매핑되지 않고 java.util.LinkedHashMap cannot be cast to ... 오류메세지가 출력되는 문제였다.
나는 DTO로 SET을 했는데, 왜 LinkedHashMap인 줄 아는거냐고. 의문에 의문이 뒤따랐다. 내부 필드 하나하나를 전부 캐싱하고 불러오는 식으로 해야하나? 하는 생각까지 들었다.
근데 Redis key를 직접 확인해보면 데이터는 잘 들어가 있는 상태였다. 그것을 보면서 내가 레디스를 뭔가 잘못 쓰고 있구나 하는 생각이 들었다.
프로젝트가 이제는 일주일가량 남았다. 사실 이제 와서 레디스를 공부하기엔 많이 촉박하다. 런칭도 해야하기때문에 이 문제를 해결하기 위해 주어진 시간은 일주일보다도 더 적다. 어차피 속성으로 배운 것, 속성으로 해결해야 했다. 그래서 이것저것 자료를 찾아보기 시작했다.
단서는 아래 블로그에서 얻었다. 감사의 뜻을 전합니다.
가장 먼저 들었던 생각은 '그러면 그동안 다른 DTO는 어떻게 매핑하고 있었던거지?' 였다.
답은 가까이에 있었다. 처음 레디스를 세팅했을 때, 그 형식을 직접 지정해준 것이었다. Jackson으로. 내가 직접. 내 손으로.
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
여기서 ValueSerializer를 설정해줬기 때문에 일반 클래스가 레디스에 잘 들어갈 수 있었던 것이다. 이 순간 깨달음을 얻었다. 그러면 이 시리얼라이저를 잘 건드리면 어떻게 잘 해볼 수 있지 않을까?
그래서 코드를 바로 건드려봤다.
public void setDto(String key, Dto object){
redisTemplate.delete(key);
redisDtoTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
redis.set(key, object);
redisTemplate.expire(key, 10, TimeUnit.MINUTES);
}
결과는 성공이었다. 해당 Dto 형식으로 값을 세팅 하는 것도, 불러오는 것도 잘 되었다. 자동으로 형식을 지정해주던 것을 명시적으로 정의해주니 잘 되는 것이다. 속성으로 공부하는 것이 이렇게 무섭다. 아마 위의 코드도 임시방편같은 것일 수 있다. 진짜 나중에 제대로 공부해서 다시 만들어봐야겠다.
뭐 아무튼 오늘도 문제 해결. 기쁘다.
추가)
문제 해결이 아니었다. template를 변경하면 해당 인스턴스에 대해서만 바뀌는 줄 알았는데 redistemplate 전체에서 바뀌는 것이었다. 야매로 적용된 기술의 한계다. 그래서 해결도 야매로 했다.
public StatDictResponseDto getDto(String key){
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Dto.class));
ValueOperations<String, Dto> redis = redisDtoTemplate.opsForValue();
Dto data = redis.get(key);
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
return data;
}
set이 아닌 get 쪽에서 값을 받아올 때만 잠깐 바꿔주고 원복하는 형식으로 해주었다.
'기술 > Spring-Boot' 카테고리의 다른 글
[Spring] Gradle은 JDK 19를 현재 지원하지 못 함 (0) | 2022.11.24 |
---|---|
스프링부트 3.0 메모.. (0) | 2022.10.22 |
[SpringBoot] FetchJoin 없이 N+1 문제 제거하기 (0) | 2022.01.10 |
[Ubuntu/nginx] 스프링 부트 및 우분투 환경에서 nginx 이용한 무중단배포 구현 (0) | 2022.01.05 |
[Ubuntu/Travis-CI/CodeDeploy] SpringBoot 환경 배포 자동화 환경 구축 (0) | 2022.01.04 |
댓글