본문 바로가기

Spring/Springboot

[Springboot] Redis를 In-memory DB로 사용하기(2)

 

 

 

 

1. 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

 

2. Configuration 

 

1) Redis와 연결: RedisConnectionFactory에 host, port를 설정하고 빈으로 등록

 

application.properties

redis.host=localhost
redis.port=6379

 

RedisConfig

@Configuration
public class RedisConfig {

    @Value("${redis.host}")
    private String host;

    @Value("${redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }

}

 

 

 

2) Redis 데이터 사용을 위한 설정

  • RedisTemplate에 RedisConnectionFactory, key serializer, value serializer를 설정하고 빈으로 등록
  • serializer가 필요한 이유
더보기

RedisTemplate을 사용하여 Redis와 상호 작용할 때, Key와 Value를 저장하고 검색하는데 사용되는 데이터는 기본적으로 Java의 객체입니다. 그러나 Redis는 내부적으로는 바이트 배열로 데이터를 저장하고 전송합니다. Serializer를 사용하면 자바 객체를 Redis에서 사용할 수 있는 바이트 배열로 변환하여 저장하고, 바이트 배열을 다시 자바 객체로 역직렬화하여 읽어올 수 있습니다.

 

Serializer를 사용하는 이유는 다음과 같습니다:

  1. 데이터 형식 일치: Redis는 다양한 데이터 형식을 지원하며, Serializer를 사용하여 자바 객체를 Redis 데이터 형식에 맞게 변환하여 저장합니다.
  2. 효율적인 전송: Serializer를 사용하면 효율적으로 데이터를 직렬화하고 전송할 수 있습니다. 특히, 바이너리 데이터를 다룰 때 중요합니다.
  3. 키/값의 유연성: Serializer를 사용하면 다양한 유형의 키와 값을 Redis에 저장할 수 있습니다. 문자열, 숫자, 객체 등 다양한 형식의 데이터를 처리할 수 있습니다.
  4. 자바 객체의 저장 및 읽기: Serializer를 사용하면 자바 객체를 Redis에 저장하고 읽을 수 있습니다. 이는 객체를 직렬화하여 저장하고 역직렬화하여 읽을 때 유용합니다.

 

RedisCLI를 사용하여 Redis 데이터를 조회할 때 문자열로 반환이 필요하기 때문에 설정!

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());   //connection
        redisTemplate.setKeySerializer(new StringRedisSerializer());    // key
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());    // value
        return redisTemplate;
    }
}

 

🤯 에러 발생

더보기

key와 vlaue를 String 으로 직렬화 

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(host, port);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());   //connection
        redisTemplate.setKeySerializer(new StringRedisSerializer());    // key
        redisTemplate.setValueSerializer(new StringRedisSerializer());  // value
        return redisTemplate;
    }
}

에러 

FileInfo cannot be cast to class java.lang.String (com.example.aifileapi.domain.FileInfo is in unnamed module of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')
 
 
FileInfo 클래스와 String 클래스 간 형변환이 잘못되었음을 알리는 에러
FileInfo 클래스는 파일 정보가 들어간 내가 만든 클래스 파일, 이 객체를 value로 넣을건데 형변환이 안되서 그렇다는 것
 
 
해결
JdkSerializationRedisSerializer를 이용하여 value값을 저장
JdkSerializationRedisSerializer는 Java의 직렬화(serialization) 메커니즘을 이용하여 데이터를 레디스에 저장하고 읽어오는 데 사용되는 Redis Serializer. Java 직렬화를 이용하여 객체를 이진 데이터로 변환하고, 그것을 레디스에 저장함. 레디스에서 데이터를 읽어올 때에도 이진 데이터를 역직렬화하여 Java 객체로 변환.
 
 
 @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());   //connection
        redisTemplate.setKeySerializer(new StringRedisSerializer());    // key
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());  // value
        return redisTemplate;
    }
 
 
 
redis-cil 확인
 
# 전체 키 조회
KEYS *

# 해당키의 value 조회
GET {키}
 

Java 직렬화를 이용하여 객체를 이진 데이터로 변환하고, 그것을 레디스에 저장했기 때문에 value가 byte형식으로 저장된 것을 확인할 수 있음

 

하지만 CLI에서 데이터를 직접 확인하고 싶다면 GenericJackson2JsonRedisSerializer()를 이용하여 json 직렬화하여 저장

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());   //connection
        redisTemplate.setKeySerializer(new StringRedisSerializer());    // key
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());    // value
        return redisTemplate;
    }

 

 json 형태로 직렬화된 데이터를 확인할 수 있음

 

 

3. Redis Entity

 

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

import java.io.Serializable;

@Builder
@Getter
@RedisHash(value = "fileInfo") 
public class FileInfo implements Serializable {
    
    @Id // Redis의 key값이 됨, null 설정 시 랜덤값 설정됨
    private String id;

    private String bizId;
    private String userId;
    private String fileId;
    private String fileName;
    private String fileExt;
    private String filePath;
    private String hasVector;
    private Long uploadTime;
}
  • @RedisHash
    • Spring Data Redis에서 엔티티 클래스를 Redis Hash로 매핑하기 위한 어노테이션
    • 이 어노테이션을 사용하여 해당 클래스 객체가 Redis의 Hash 데이터 구조에 저장 됨
  • @RedisHash 속성
    • value: 필수 속성
@RedisHash("Redis에서 사용할 Hash 이름")
@RedisHash(value="Redis에서 사용할 Hash 이름")

 

 

  • timeToLive: Hash의 유효 기간 설정, 이 속성을 지정하지 않으면 기본값 -1이 정의되고 -1의미는 만료시간 없음(수동으로 삭제하거나 다른 정책에 의해 삭제될 때 까지 데이터 영구 저장)
@RedisHash(timeToLive = 60 * 60 * 24 * 30) // 30일 
@RedisHash(timeToLive = 3600) // 1시간

 

  • 기타 속성
더보기

 

  1. idSpace:
    • Redis에서 유일한 식별자를 생성하는데 사용되는 네임 스페이스를 지정합니다.
    • 예: @RedisHash(value = "myHash", idSpace = "myNamespace")
  2. hashKeyAlgo:
    • Hash의 키를 생성하는 알고리즘을 지정합니다.
    • 예: @RedisHash(value = "myHash", hashKeyAlgo = HashAlgo.MURMUR_HASH)
  3. hashKeys:
    • Hash의 키로 사용할 필드를 지정합니다. 여러 개의 필드를 배열로 지정할 수 있습니다.
    • 예: @RedisHash(value = "myHash", hashKeys = {"field1", "field2"})
  4. index:
    • Hash 내에서 인덱스를 생성할 필드를 지정합니다. 여러 개의 필드를 배열로 지정할 수 있습니다.
    • 예: @RedisHash(value = "myHash", index = {"indexField1", "indexField2"})
  5. indexes:
    • index와 동일한 역할을 하지만 여러 개의 인덱스를 한 번에 설정할 수 있습니다.
    • 예: @RedisHash(value = "myHash", indexes = {@Index(name = "index1", value = "indexField1"), @Index(name = "index2", value = "indexField2")})
  6. writeTtl:
    • 쓰기 작업에 대한 타임아웃(초 단위)을 설정합니다.
    • 예: @RedisHash(value = "myHash", writeTtl = 10)
  7. forceKeyspace:
    • true로 설정하면 키 스페이스가 강제로 지정됩니다. 기본값은 false입니다.
    • 예: @RedisHash(value = "myHash", forceKeyspace = true)

 

4. Redis Repository

import org.springframework.data.repository.CrudRepository;

public interface FileInfoRedisRepository extends CrudRepository<FileInfo, String> {
   
}