본문 바로가기
Spring/SpringBoot

[SpringBoot] Redis 사용하기 (2) - Redis Repository 사용하기

by J4J 2024. 5. 12.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 redis 사용하기 두 번째인 redis repository 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

이전 글

 

[SpringBoot] Redis 사용하기 (1) - Redis란 무엇인가?

 

 

반응형

 

 

Redis Repository란 ?

 

redis repository는 인터페이스 기반으로 redis의 CRUD 처리를 수행하는 방식을 제공합니다.

 

redis repository와 가장 유사한 방식으로 사용되는 것은 jpa repository가 있습니다.

 

 

 

jpa repository의 상속 관계를 살펴보면 상위에 ListCrudRepository와 CrudRepository 등이 존재합니다.

 

그리고 redis repository는 CrudRepository를 상속 받아 redis 기능들을 활용하는 방식입니다.

 

그래서 jpa와 동일하게 상위 인터페이스로부터 상속 받은 findById / findAll 등의 메서드들을 redis repository에서도 사용할 수 있습니다.

 

또한 findBy~ 메서드를 정의하여 원하는 변수 값을 이용하여 데이터를 조회할 수 있습니다.

 

Repository 구조

 

 

 

또한 jpa repository 에서 테이블에 매핑되는 객체 엔티티가 관리되는 것처럼 redis repository에서도 매핑되는 객체 엔티티가 존재해야 합니다.

 

redis로 관리되고 싶은 데이터들로 구성된 객체를 정의하여 redis repository에 연결해주면 jpa처럼 사용 해볼 수 있습니다.

 

 

 

 

Redis Repository 사용 환경 설정

 

이번에는 redis repository를 활용할 수 있도록 환경 설정을 해보겠습니다.

 

간단한 예시로 사용자 정보를 redis에 저장하는 코드를 작성하면 다음과 같습니다.

 

 

 

[ 1. dependency 추가 ]

 

dependencies {
    // redis
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}

 

 

 

[ 2. redis properties 추가 ]

 

// application.yml
spring:
  data:
    redis:
      host: localhost # redis host 입력
      port: 6379 # redis port 입력

 

 

 

[ 3. redis config 클래스 추가 ]

 

package com.jforj.redisrepository.config;

import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@Configuration
@RequiredArgsConstructor
public class RedisConfig {
    private final RedisProperties redisProperties;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(
                new RedisStandaloneConfiguration(
                        redisProperties.getHost(),
                        redisProperties.getPort()
                )
        );
    }
}

 

 

 

 

[ 4. user entity 추가 ]

 

package com.jforj.redisrepository.entity;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

@RedisHash("user") // hash 기반의 key-value를 구성하여 데이터 저장
@Builder
@Getter
@ToString
public class User {
    @Id // 객체를 식별하기 위해 사용되는 key 값
    private String id;
    private String name;
}

 

 

 

entity를 확인해보면 redis를 위해 사용되는 어노테이션들이 존재합니다.

 

먼저 @RedisHash는 hash 기반의 key-value를 구성하여 데이터를 저장할 수 있도록 도와줍니다.

 

그래서 위와 같이 설정을 하여 redis에 데이터를 저장하게 되면 "user:"의 형태로 prefix가 추가되어 있는 것을 확인할 수 있습니다.

 

 

 

다음으로 @Id는 객체를 유니크하게 식별하기 위해 사용되는 key 값입니다.

 

즉, 위의 entity 같은 경우는 @RedisHash에 설정한 key 값을 통해 user entity 정보들을 모두 찾게되고 이들 중 @Id로 설정되어 있는 값을 통해 유니크한 user entity를 조회하게 됩니다.

 

그러다보니 redis에서 key를 조회해보면 @RedisHash값과 @Id값이 함께 key로 구성되어 있는 것을 볼 수 있습니다.

 

 

 

[ 5. user redis repository 추가 ]

 

package com.jforj.redisrepository.repository;

import com.jforj.redisrepository.entity.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, String> {

}

 

 

 

 

위에서 작성한 코드들이 올바르게 동작하는지 테스트를 해보겠습니다.

 

redis repository 테스트 코드를 작성한 뒤 각각 실행해보면 다음과 같은 결과를 확인할 수 있습니다.

 

// user repository test
package com.jforj.redisrepository.repository;

import com.jforj.redisrepository.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void create() {
        List<User> users = List.of(
                User.builder()
                        .id("first id")
                        .name("first name")
                        .build(),
                User.builder()
                        .id("second id")
                        .name("second name")
                        .build()
        );

        userRepository.saveAll(users);
    }

    @Test
    void selectAll() {
        userRepository.findAll().forEach(user -> System.out.println(user));
    }
}

 

create test

 

redis key 정보

 

selectAll test

 

 

 

 

인덱싱 처리

 

redis repository를 사용할 때 @Id로 정의한 key 값을 제외하고도 redis에 저장된 데이터를 조회할 수 있도록 인덱싱 처리를 제공해주고 있습니다.

 

또한 인덱싱 되어 있는 값을 이용하여 더 빠른 속도로 데이터를 조회할 수도 있습니다.

 

 

 

인덱싱 처리를 하는 방법으로 @Indexed 어노테이션을 활용할 수 있습니다.

 

위의 user entity에서 name을 인덱싱 처리하는 코드로 변경한다면 다음과 같이 작성 해볼 수 있습니다.

 

// user entity
package com.jforj.redisrepository.entity;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

@RedisHash("user") // hash 기반의 key-value를 구성하여 데이터 저장
@Builder
@Getter
@ToString
public class User {
    @Id // 객체를 식별하기 위해 사용되는 key 값
    private String id;
    @Indexed // 인덱싱 처리
    private String name;
}

 

 

 

 

인덱싱 처리에 대한 테스트를 진행해보겠습니다.

 

먼저, 만약 user entity에 인덱싱 처리를 하지 않고 다음과 같은 테스트를 진행해보면 의도하지 않은 결과를 확인할 수 있습니다.

 

// user repository
package com.jforj.redisrepository.repository;

import com.jforj.redisrepository.entity.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, String> {

    /**
     * name을 이용하여 user 조회
     */
    User findByName(String name);
}



// user repository test
package com.jforj.redisrepository.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void selectName() {
        System.out.println(userRepository.findByName("first name"));
    }
}

 

인덱싱 처리 전 selectName test

 

 

 

하지만 위와 같이 user entity에서 name을 인덱싱 처리한 뒤 데이터를 새롭게 적재 및 조회를 해보면 다음과 같은 결과를 확인할 수 있습니다.

 

인덱싱 처리 후 create test

 

인덱싱 처리 후 redis key 정보

 

인덱싱 처리 후 selectName test

 

 

 

 

유효 시간 설정

 

redis repository에서는 redis에 저장되어 있는 데이터의 TTL 설정을 통해 유효 시간을 제공해주고 있습니다.

 

TTL 설정하지 않는 경우에는 default 값으로 유효 시간이 따로 적용되지 않기 때문에 임의로 삭제 처리를 하지 않은 경우 계속 유효한 데이터로 남아 있습니다.

 

 

 

유효 시간을 설정하는 방법은 2가지가 있습니다.

 

첫 번째는 @RedisHash 어노테이션의 timeToLive 값을 설정하면 됩니다.

 

다음과 같이 코드를 변경하면 모든 user entity의 유효 시간을 60초로 설정할 수 있고, 데이터를 새롭게 적재한 뒤 60초 뒤에 데이터를 조회해보면 다음과 같은 결과를 확인할 수 있습니다.

 

// user entity
package com.jforj.redisrepository.entity;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

@RedisHash(value = "user", timeToLive = 60) // hash 기반의 key-value를 구성하여 데이터 저장 (유효 시간 60초로 설정)
@Builder
@Getter
@ToString
public class User {
    @Id // 객체를 식별하기 위해 사용되는 key 값
    private String id;
    @Indexed // 인덱싱 처리
    private String name;
}

 

유효 시간 만료 전 redis key 정보

 

유효 시간 만료 전 selectAll test

 

유효 시간 만료 후 redis key 정보

 

유효 시간 만료 후 selectAll test

 

 

 

 

두 번째는 @TimeToLive 어노테이션을 이용하는 방식입니다.

 

@TimeToLive 어노테이션은 entity 필드 정보에 유효 시간 변수를 추가해줘야 합니다.

 

다음과 같이 코드를 변경하면 첫 번째 방식과 달리 동일한 user entity여도 각 entity 객체 별로 서로 다른 유효 시간을 설정 해볼 수 있습니다.

 

// user entity
package com.jforj.redisrepository.entity;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.TimeToLive;
import org.springframework.data.redis.core.index.Indexed;

@RedisHash("user") // hash 기반의 key-value를 구성하여 데이터 저장
@Builder
@Getter
@ToString
public class User {
    @Id // 객체를 식별하기 위해 사용되는 key 값
    private String id;
    @Indexed // 인덱싱 처리
    private String name;
    @TimeToLive // TTL 설정
    private Long expiration;
}


// user repository test
package com.jforj.redisrepository.repository;

import com.jforj.redisrepository.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void create() {
        List<User> users = List.of(
                User.builder()
                        .id("first id")
                        .name("first name")
                        .expiration(60L) // TTL 60초
                        .build(),
                User.builder()
                        .id("second id")
                        .name("second name")
                        .expiration(30L) // TTL 30초
                        .build()
        );

        userRepository.saveAll(users);
    }
}

 

유효 시간 만료 전 redis key 정보

 

유효 시간 만료 전 selectAll test

 

30초 후 redis key 정보

 

30초 후 selectAll test

 

60초 후 redis key 정보

 

60초 후 selectAll test

 

 

 

 

 

 

 

 

이상으로 redis 사용하기 두 번째인 redis repository 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글