ValueOperation이란?
ValueOperations<K,V>는 SpringDataRedis에서 StringRedisTemplate를 통해 Redis의 “Value”관련 연산을 수행하는 인터페이스이다.
Redis에서 key-value형식으로 데이터를 저장하는데 이 때 ValueOperations는 Redis의 “String 타입” 데이터를 다루는데 사용된다.
ValueOperations의 주요 역할
데이터 읽기 작업
String value = redisTemplate.opsForValue().get("key");
데이터저장
redisTemplate.opsForValue().set("key", "value");
숫자증가
redisTemplate.opsForValue().increment("counter");
숫자감소
redisTemplate.opsForValue().decrement("counter");
왜 ValueOperations를 반환해서 사용하는가?
RedisTemplate 자체는 다양한 자료구조를 지원하지만, 각 자료구조를 다루는 방식은 다르다.
RedisTemplate의 각 opsForXXX()메서드는 해당 자료구조에 맞는 Operation 인터페이스를 반환해야한다. 해당 자료구조에 맞는 API를 사용할 수 있게 해준다.
데이터 타입 인터페이스 사용 메서드
String (단일 값) | ValueOperations | opsForValue() |
Hash | HashOperations | opsForHash() |
List | ListOperations | opsForList() |
Set | SetOperations | opsForSet() |
SortedSet | ZSetOperations | opsForZSet() |
HyperLogLog | HyperLogLogOperations | opsForHyperLogLog() |
Stream | StreamOperations | opsForStream() |
Redis의 데이터 구조별로 Operation 인터페이스가 존재하기 때문에
- RedisTemplate은 다양한 Redis 자료구조를 다룰 수 있게 설계되어 있다.
- 특정 자료구조를 사용하려면, 자료구조에 해당하는 인터페이스를 사용해야 한다.
- ValueOperations는 Redis의 기본 자료구조인 String 타입 데이터를 다루기 위한 전용 인터페이스 입니다.
타입별로 제공되는 메서드가 다르기 때문에
- RedisTemplate에서 opsForValue() 메서드를 호출하면 ValueOperations 객체가 반환된다.
- ValueOperations 인터페이스에는 String 타입 데이터를 다루기 위한 다양한 메서드가 포함되어 있.
- 다른 자료구조(Hash, List, Set, SortedSet)를 사용하려면 각 자료구조에 맞는 인터페이스를 사용해야 한다.
테스트 코드 실사용 예제
@ExtendWith(MockitoExtension.class)
class ViewCountRedisRepositoryTest {
@Mock
StringRedisTemplate redisTemplate;
@Mock
ValueOperations<String, String> valueOperations;
@InjectMocks
ViewCountRedisRepository viewCountRedisRepository;
@Test
@DisplayName("특정 게시글 조회수 조회")
void readPostViewCount() {
// Given
String key = "post:1:view_count";
given(redisTemplate.opsForValue()).willReturn(valueOperations);
given(valueOperations.get(key)).willReturn("100");
// When
Long result = viewCountRedisRepository.read(1L);
// Then
assertThat(result).isEqualTo(100L);
}
}
given(redisTemplate.opsForValue()).willReturn(valueOperations); 해당 구문을 통해 redisTemplate.opsForValue 호출 될 때 ValueOperations 객체를 반환하도록 한 설정이다.
redisTemplate.opsForValue()는 ValueOperations<K, V> 인터페이스를 반환하는데, 이는 기본적으로 null이므로 테스트 실행 시 NullPointerException이 발생할 수 있습니다.
Redis - ValueOperaion 테스트 코드 작성 시
public void insert(Long postId, Long userId) {
String key = generateKey(postId, userId);
postLikeRedisTemplate.opsForValue().set(key, "");
}
public void delete(Long postId, Long userId) {
String key = generateKey(postId, userId);
postLikeRedisTemplate.delete(key);
}
- insert메서드는 opsForValue를 통해 set 함수를 호춯함
- delete메서드는 delete를 호출할 때 opsForValue를 호출하지 않음
이유
insert()는 Redis에 key-value 형태로 데이터를 저장해야 하므로 opsForValue()가 필요하다.
delete()는 key 자체를 삭제하면 되므로 opsForValue() 없이postLikeRedisTemplate.delete(key)만 호출
두 메서드는 각기 다른 Redis 동작을 수행하므로, opsForValue() 사용 여부가 다름!
@Test
@DisplayName("특정 유저가 특정 게시글에 좋아요를 처음 눌렀을 경우 key를 insert한다.")
void insert() {
//given
given(template.opsForValue()).willReturn(valueOperations);
//when
repository.insert(1L, 1L);
//then
then(valueOperations).should(times(1)).set(anyString(), anyString());
}
@Test
@DisplayName("특정 유저가 특정 게시글에 좋아요를 처음 눌렀을 경우 key를 insert한다.")
void delete() {
//given
//when
repository.delete(1L, 1L);
//then
then(template).should(times(1)).delete(anyString());
}
그렇기 때문에 opsForValue를 사용한 함수 호출 시 에는valueOperation을 반환해주고, delete는 바로 Redis로 직접 접근하면 된다.
'프로젝트 이슈 및 몰랐던점 정리 > CommunityAPI' 카테고리의 다른 글
[학습 포인트] 💡Mockito Matchers와 실제 값을 이용한 테스트의 차이 (0) | 2025.03.30 |
---|---|
[학습 포인트]💡 MockMvc 컨트롤러 단위 테스트 시 인증정보 부재 (0) | 2025.03.30 |
[트러블 슈팅] ⚠️A component required a bean named 에러 원인 (0) | 2025.03.30 |
[트러블 슈팅] ⚠️ 읽기 전용 트랜잭션 내 쓰기 작업 문제와 REQUIRES_NEW 전파 전략 활용(self invocation) (0) | 2025.03.30 |
[트러블 슈팅] ⚠️ Spring Boot LocalDateTime 변환 에러 해결법 (@JsonFormat vs @DateTimeFormat) (0) | 2025.03.09 |