고인물을 지양하는 블로그

[Spring Data Redis] Redis Repository로 저장한 도메인 Redis Template로 접근 본문

카테고리 없음

[Spring Data Redis] Redis Repository로 저장한 도메인 Redis Template로 접근

yunjaeGong 2022. 9. 22. 23:54

Spring Boot Redis를 이용해 Redis에 접근하는 방법에는 크게 

1. RedisTemplate를 이용하는 방법

2. RedisRepository를 이용하는 방법

 

두 가지 방법이 있다.


Redis Template을 이용하는 방법

https://sabarada.tistory.com/105?category=856943 

 

[Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisTemplate 편

[Redis] 캐시(Cache)와 Redis [Redis] Redis의 기본 명령어 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisTemplate 편 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisRepository..

sabarada.tistory.com

Redis Repository를 이용하는 방법

https://sabarada.tistory.com/106?category=856943 

 

[Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisRepository 편

[Redis] 캐시(Cache)와 Redis [Redis] Redis의 기본 명령어 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisTemplate 편 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisRepository..

sabarada.tistory.com

 

Spring-Redis-Document와 위 블로그에 각 방법을 이용하는 방법이 잘 나와있지만, 이 글에서는 한 번에 둘 다 이용하는 방법을 알아보고자 한다.


RedisTemplate Serializer 설정

1. Serializer가 필요한 이유

Java에서 사용하는 data type은(e.g., int, Person, Meeting Class) 자바 애플리케이션 내에서는 선언한 타입처럼 취급되지만, 외부에서는 단순히 이진 데이터일 뿐, 그 자체가 의미를 가지지는 못한다.

Java 애플리케이션에서 Redis로 데이터가 전달될 때, Redis에서 이진 데이터가 Redis Data Type으로 취급되고, 그 역도 가능하게 하기 위해 Serializer가 위 업무를 수행한다.

 

Spring-Data-Redis는 여러가지 Serializer를 제공하고 있다.

 

2. Serializer 종류 및 트러블슈팅

1) 기본 설정

 JdkSerializationRedisSerializer

  RedisTemplate, RedisCache의 기본 Serializer이다.

2) SpringSerializer

  bytebuffer에 읽 byte[] 

3) SpringRedisSerializer

사람이 읽기 쉽도록 String 기반 인코딩을 통해 Key Value를 

 

* RedisConnection 이용하는 경우에는 StringRedisConnection 이용

 

Redis Repository를 이용하면 쉽게 도메인 객체를 Serialize 및 저장할 수 있으며, CrudRepository를 구현하는 레포지토리는

save(), deleteBy...(), removeBy...() 메서드를 통해 기본적인 CRUD 기능을 제공하며, findBy...() 메서드로 탐색 부가기능까지 제공하며, Spring-Data-JPA와 같은 인터페이스로, 애플리케이션 개발 시 편리하다.

 

반면에 Redis Template은 Redis 인스턴스 이용에 있어 다양한 접근 방법을 제공하는데, 

Key Type Operations
GeoOperations Redis geospatial operations, such as GEOADD, GEORADIUS,…​
HashOperations Redis hash operations
HyperLogLogOperations Redis HyperLogLog operations, such as PFADD, PFCOUNT,…​
ListOperations Redis list operations
SetOperations Redis set operations
ValueOperations Redis string (or value) operations
ZSetOperations Redis zset (or sorted set) operations
Key Bound Operations
BoundGeoOperations Redis key bound geospatial operations
BoundHashOperations Redis hash key bound operations
BoundKeyOperations Redis key bound operations
BoundListOperations Redis list key bound operations
BoundSetOperations Redis set key bound operations
BoundValueOperations Redis string (or value) key bound operations
BoundZSetOperations Redis zset (or sorted set) key bound operations

위처럼 redis datatype 각각에 대응하는 접근 메서드를 제공하고 있다.

 

그렇다면, RedisTemplate로 아래와 같이 저장된 값을 Redis Template을 통해 어떻게 읽을 수 있을까?

 

redis cli 기본 명령

더보기

 

type 'key'

'key'에 대응하는 엔트리가 가지는 값의 타입 반환

https://redis.io/docs/data-types/

 

Redis data types

Overview of data types supported by Redis

redis.io

hget 'key' 'hashkey'

key와 hashkey에 해당하는 레코드가 가지는 값 반환

hgetall 'key'

해당 'key'에 연관된 hashkey, 값을 (hashkey, value, hashkey, value 순으로) 반환

hkeys 'key'

해당 'key'에 연관된 hashkey를 반환

hvals 'key'

해당 'key'에 연관된 값을 반환

keys 'pattern'

redis가 가지는 'key' 중, 해당 'pattern'에 대응하는 key들을 반환

Redis Repository를 이용한 영속화

위와 같은 Meeting class를 redis에 저장하자.

 

Redis Repository 이용

// Redis Repository를 이용하는 방법
Meeting meeting = new Meeting();
meeting.setTitle("New Meeting 1");
meeting.setStartAt(new Date());
meetingRepository.save(meeting);

위 명령을 통해 Redis에는 두 개의 Meeting 클래스의 오브젝트가 저장돼 있다 가정하자

key와 hashkey

Meeting과 관련된 모든 키를 관리하는 Meetings의 데이터 타입은 set이다.

 

그리고 저장된 레코드의 데이터 타입은 hash이다.

우리가 찾는 Meeting 오브젝트와 관련된 프로퍼티는 hash타입 Meetings:xxxxxxx-xxxx-... 에 저장돼 있다.

 

위 예시를 통해 두 가지 사실을 알 수 있다.

1. Redis Repository를 통해 저장된 오브젝트는 엔티티의 @RedisHash('key') 어노테이선에 명시한 key와 id를 조합한 hash 타입으로 저장된다.

    -> Redis Repository를 통해 저장된 오브젝트의 'key'는 {Meetings:@id 프로퍼티 값} 이다.

 

2. Meeting 오브젝트들은 hash 타입들의 set 형태로 저장된다.

 

따라서 오브젝트의 프로퍼티들은 hash 명령을 통해 접근할 수 있다.

hgetall: 해당 'key'에 연관된 모든 프로퍼티를 반환하는 명령
set: 해당 'key'에 연관된 모든 멤버를 반환하는 명령

이 사실을 통해, Meetings 키에는 set 관련 명령, Meetings: + id 키에는 hash 관련 명령을 사용해야 한다는 것을 알 수 있다.


추가 정보

 

Spring Data Redis

Some commands (such as SINTER and SUNION) can only be processed on the server side when all involved keys map to the same slot. Otherwise, computation has to be done on client side. Therefore, it is useful to pin keyspaces to a single slot, which lets make

docs.spring.io


Redis Repository와 Redis Template 동시에 사용하기

저장된 오브젝트의 데이터 타입에 대한 정보를 바탕으로, Redis Repository를 이용해 저장된 값을 RedisTemplate를 이용해 읽는 방법은 다음과 같다.

 

* Serializer의 종류 트러블슈팅에서 다룬 것처럼, java 애플리케이션에서 쓴 값을 Redis cli에서 편히 읽기 위해서는 Serializer 설정이 필요하다.

 

* Redis Template과 Redis Cache의 기본 Serializer인 JdkSerializationRedisSerializer 대신, StringRedisSerializer를 사용했다.

@Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());  
        // serializer 변경
        
        return redisTemplate;
    }

 

Redis Repository로 저장한 객체 불러오기

void redisTemplate_opsForHash_approach() {
        Map<Object, Object> results = 
                redisTemplate.opsForHash().entries("Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5");
         // key에 연관된 모든 hashkey, value의 반환
         
        System.out.println("----------redisTemplate_opsForHash_approach----------");
        
        System.out.println("entry size: " + results.size()); // 엔트리 크기
        results.forEach((k, v) -> System.out.println(
                "key: \"" + k.toString()
                + "\" val : \"" + v.toString() + "\""));

    }

java 결과

hgetall Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5

명령을 이용한 것과 같은 결과임을 알 수 있다.

redis cli 결과


번외

Redis Template 이용해 값 수정

void redisTemplate_opsForHash_modify_property() {
    System.out.println("----------redisTemplate_opsForHash_modify_property----------");

    // given
    Map<Object, Object> results =
            redisTemplate.opsForHash().entries("Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5");
    assertNotNull(results);
    System.out.println(results);
    String orig_title = results.get("title").toString();

    // when
    redisTemplate.opsForHash().put("Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5", "title", "RedisTemplate modification");
    System.out.println("----------After Modification----------");

    // then
    results = redisTemplate.opsForHash().entries("Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5");
    assertNotNull(results);
    assertNotNull(results.get("title").toString(), "RedisTemplate modification");

    System.out.println(results);

    redisTemplate.opsForHash().put("Meetings:94c9e99e-94a6-4c08-8137-7782dc744ca5", "title", orig_title);

}


도큐먼트를 보며 공부하다 Redis Repository를 이용해 저장한 값을 Redis Template을 통해 어떻게 접근할까?라는 궁금증에 Redis Template과의 싸움을 시작했고 글로 남기게 되었습니다.

 


2022/11/07 추가

 

Spring Data Redis 도큐먼트를 살펴보다 StringRedisSerializer와 관련된 RedisTemplate / RedisConnection 관련 클래스를 찾을 수 있었습니다.

 

Spring Data Redis

Some commands (such as SINTER and SUNION) can only be processed on the server side when all involved keys map to the same slot. Otherwise, computation has to be done on client side. Therefore, it is useful to pin keyspaces to a single slot, which lets make

docs.spring.io

항목에서, String 위주(String key, value를 가지는) 작업을 수행할 때, 별도 Serializer 설정 없이 사용할 수 있는 클래스로, StringRedisTemplate, StringRedisConnection 클래스를 제공하고 있다는 것을 알게 되었습니다. 

 

위 예시는 StringRedisTemplate + StringRedisSerializer 설정을 통해  사람이 읽을 수 있는 String 작업을 수행하고 있지만, 바로 위에서 소개한 클래스를 이용하면 별도 설정 없이도 기본 Serializer로 StringRedisSerializer를 이용하는 것으로 보입니다.

 

 

Comments