개발 기록

> [Redis] Redis 구현 방법 차이 - RedisTemplate, RedisRepository, @Cacheable 본문

SQL&NoSQL

> [Redis] Redis 구현 방법 차이 - RedisTemplate, RedisRepository, @Cacheable

1z 2024. 2. 4. 19:21

 

0. 기본 차이점 정리 

  RedisManager RedisTemplate RedisRepository
  ☞ Spring Cache 추상화
☞ return value chching
☞ 데이터 타입별로 방식 다름 ☞ CRUD Repository 상속
☞ @RedisHash Entity
 저장 @Cacheable(name = "item") redisTemplate
.opsForValue().set(key, value)
redisRepository.save(entiyu)
조회 @Cacheable(name = "item") redisTemplate
.opsForValue().get(key)
redisRepository.findById(key)
삭제 @CacheEvict redisTemplate
.opsForValue().delete(key)
redisRepository.delete()
장점 구현 쉬움, 캐시 로직 분리 가능 여러 자료구조 타입을 선택가능 간편 사용
단점 only return value caching   트랜잭션 지원하지 않음,  
set, hash 구조를 사용

 

 

1. 기본 사용법 

 

1-2. RedisRepository 

Jpa Data Repository 형태로 Redis CRUD 기능을 지원한다. 

- 간단하고 일관된 CRUD 작업이 주된 작업의 경우에 적합하다.
- Redis 데이터에 대한 공통 작업을 더 편리하게 처리할 수 있는 고수준의 메서드를 제공한다. 
- 직접 Redis 작업을 구현할 필요 없이 Spring Data Redis의 기능을 활용할 수 있다.
- set으로 key를 만들고 하위 key-value를 hash로 한다.

 

1. Entity  생성 

    • @RedisHash 을 도메인 클래스에 선언 : User 객체를 레디스의 Hash 자료구조로 저장
    • User 는 key(=필드이름) : value 형태로 값을 저장하고 있으며, getter로 value를 가져온다
    • ex. User:id 
    •  
@RedisHash("User") // Redis 키 prefix
public class User implements Serializable {

	@Id
    	private String id;
      	private String name;
}

 

 

 

2. CrudRepository를 상속받는 UserRepository  생성

@Repository
public interface UserRepository extends CrudRepository<Usert, String> {}

 

 

3. Spring Data Repository로 데이터 접근하기

public Member getMember(){
    // 저장 
    User user = new User();
    userRepoistory.save(user);
    
    // 조회
    Member findMember = userRepoistory.findById("id");

	// 삭제
    studentRepository.deleteById("id");
 }

 

 

 단점 

 

1.  특정 Entity 만 캐싱하기 때문에 다양한 데이터 타입을 저장할 수 없다.


 

1-2. 캐시 추상화 - Annotaion  기반 Caching 


캐시 추상화를 통해 코드에 미치는 영향을 최소화 하면서 캐싱을 일관되게 가능하게 한다.

spring 3.1 부터 지원

 

1. 어노테이션 유형 

유형  기능
@Cacheable 캐시에 데이터가 있으면 :  메서드 로직을 실행 x => 캐시에서 데이터 조회/ 반환.
캐시에 데이터가 없다면 : 메서드 내부의 로직을 실행 후 => 캐시에 저장 후  반환

@CacheEvict 캐시 제거
@CachePut 캐시 업데이트
: 내부의 로직을 실행후 캐시에 데이터 저장 및 반환
@Caching 캐시 작업 그룹화
@CacheConfig 클래스 단에서 캐시 설정 공유

 

2. 속성 

 

 

 

3. 사용법

1. @EnableCaching 

캐시 어노테이션을 선언한다고 해서 캐싱 작업이 자동으로 실행되지는 않는다

@EnableCaching 선언으로 캐시 동작을 활성화 한다.  @EnableCaching 은 RedisCacheManager를 자동 구성한다.

@Configuration
@EnableCaching
public class CacheConfig{
}

 

2. @Cacheable

/**속성
cacheNames : 캐시 이름
value : cacheNames 의 alias 
key : 키값 (동일한 cacheName 끼리 구분)
allEntries : 캐시 전체 제거 여부
KeyGenerator : 키 생성
cacheManager : 사용 할 CacheManager 지정
sync : 캐싱 동기화 
unless : 캐싱하지 않는 조건 (ex. #result == null)
condition : 조건부 캐싱 (ex. "#id==1")
*/

@Cacheable(
cacheNames = "platformTeamBooks", 
value = "itemCache",
key = "#root.target + #root.methodName + '_'+ #p0",
unless="#id.equals('1')"
sync= true,
condition ="#result == null")
public Item getItemForId(String id) {
    return itemRepository.findById(id)
      .orElseThrow(RuntimeException::new);
}

 

 

단점 

 

1. 반환되는 데이터를 캐시에 저장한다는 한계가 있어서 메인 로직 실행 도중에 반환 데이터가 아닌 다른 부분 데이터를 캐시에 저장 할 수 없다. (이럴때는 RedisTemplate, RedisRepository 사용)

다만, @CacheEvict 같은 경우 캐시 내에 key 값에 해당하는 데이터를 제거하는 것이므로, 반환되는 데이터에 제한받지 않는다.

 

2.  GenericJackson2JsonRedisSerializer()을 통한 직렬화 방식은 문제 는 (https://khdscor.tistory.com/100 참고)

 


 

3. RedisTemplate  

- Redis 연산, 예외 변환, 트랜잭션, 직렬화 커스텀 기능 제공
- Redis 트랜잭션 기능: Redis는 싱글 쓰레드, Atomic한 자료구조로 RaceCondition을 피할 수 있다.

- 특정 Entity 이외에도 여러 자료구조 타입을 선택할 수 있다.(문자열, 해시, 목록, 집합, 정렬된 집합 등)용
- 객체들을 자동으로 직렬화/역직렬화하며 binary 데이터를 Redis에 저장한다. 

 

1. Redis Template  Bean 생성

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
public void do(){
 
    // String 
    redisTemplate.opsForValue().set(role.getId(), role);
     
    // 리스트
    redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
    
    // 등등
}

 

 

※ 단점

데이터 타입별로  ops 인터페이스 가 다르고 구현하는 메서드도 다르기 떄문에 코드 작업이 많아진다.

 

 

 

 

 

 

 

 

 

 

참고

https://docs.spring.io/spring-framework/reference/integration/cache/annotations.html#cache-spel-context

https://jiwondev.tistory.com/282

https://loosie.tistory.com/807#2._RedisTemplate_(low_level)