개요
스프링에는 Redis와 연동하는 여러가지 방법이 존재하는데 Data JPA와 비슷하게 Data Redis라는 라이브러리를 제공한다. Lettuce와 Jedis 2가지 구현체를 통해 통신할 수 있는 방법이 있는데, Lettuce는 별다른 추가 설정없이 사용할 수 있지만 Jedis는 추가적인 의존성이 필요하다. 요즘에는 아래의 이유로 인해 Jedis보다 Lettuce를 쓰는 추세라고 한다.
- Lecttue는 비동기로 요청을 처리하기 때문에 성능적인 이점이 있음
- Lecttue는 Jedis와는 다르게 별도의 풀을 생성하지 않아도 되기 때문에 개발이 단순함
- Jedis는 Thread-safe하지 않고 Spring boot 2.0부터 deprecated됨
본 포스팅에서는 Data Redis를 통해 스프링에서 Redis와 통신하는 방법에 대해 기술한다.
Data Redis에서는 RedisTemplate, RedisRepository 총 2가지의 방법을 제공한다. 설정부터 2가지의 방법을 하나하나 살펴보자.
설정 및 의존성 설치
spring:
redis:
host: localhost
port: 6379
먼저 application.yml파일을 열고 아래의 라인을 추가한다. 설정은 다른 방법을 사용할수도 있지만 본 포스팅에서는 최대한 간단한 설정을 위해 yml파일에 작성했다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
다음으로 build.gradle을 열고 dependencies부분에 data-redis를 추가해준다.
RedisTemplate
@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<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
먼저 RedisConfig라는 클래스를 하나 생성해준다. 위에서 application.yml에 레디스 관련 host, port를 넣어줬기 때문에 @Value를 통해 해당 값을 가져와서 채워주기로 한다. 위 설정은 RedisRepository가 아닌 RedisTemplate를 통해 레디스와 통신하기 위한 설정값이다.
String 타입
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final RedisTemplate<String, String> redisTemplate;
public void testRedisString() {
ValueOperations<String, String> operation = redisTemplate.opsForValue();
String key = "string";
operation.set(key, "test");
operation.get(key);
System.out.println(key);
}
}
String타입은 opsForValue() 메소드를 사용하며 set(), get() 등의 메소드를 지원한다.
Set 타입
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final RedisTemplate<String, String> redisTemplate;
public void testRedisSet() {
SetOperations<String, String> operation = redisTemplate.opsForSet();
String key = "set";
operation.add(key, "h", "i", "d", "e");
Set<String> members = operation.members(key);
System.out.println(members);
}
}
Set타입은 opsForSet() 메소드를 사용하며 add(), members() 등의 메소드를 지원한다.
Hash 타입
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final RedisTemplate<String, String> redisTemplate;
public void testHash() {
HashOperations<String, Object, Object> operation = redisTemplate.opsForHash();
String key = "hash";
operation.put(key, "hide", "test");
Object value = operation.get(key, "hide");
System.out.println(value);
}
}
Hash타입은 opsForHash() 메소드를 사용하며 get(), put() 등의 메소드를 지원한다.
RedisRepository
RedisRepository를 사용하면 객체를 손쉽게 Hash타입의 자료구조로 변환하여 사용할 수 있다.
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
@Getter
@RedisHash(value = "user")
public class RedisUser {
@Id
private Long id;
private String name;
public RedisUser(Long id, String name) {
this.id = id;
this.name = name;
}
}
먼저 위처럼 사용할 객체를 만든다. 위 예제에서는 간단하게 id, name이라는 2개의 필드만을 가진 RedisUser라는 클래스를 만들었다. @RedisHash의 value값에 특정한 값을 넣어줌으로써 추후 키를 생성할 때 prefix를 지정해줄 수 있다. 또한 @Id 어노테이션을 사용하여 prefix:구분자 형태로 값을 구분한다. 참고로 @Id 어노테이션은 코드에 나와있는 것 처럼 org.springframework.data.annotation.Id를 사용해야 한다.
만약 TTL을 주고 싶다면 RedisHash에 timeToLive옵션에 정수값을 넣어주자
public interface UserRedisRepository extends CrudRepository<RedisUser, Long> {
}
다음으로 CrudRepository를 상속받은 Repository 인터페이스를 만들어준다. 이 부분은 Data Jpa와 완전히 동일하다.
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final UserRedisRepository userRedisRepository;
public void createUser() {
RedisUser user = new RedisUser(1L, "hide");
userRedisRepository.save(user);
}
}
저장 또한 Data Jpa와 마찬가지로 객체를 생성하고 Repository의 save() 메소드를 통해 저장할 수 있다. 저장 후 Redis에서 키를 살펴보면
127.0.0.1:6379> keys *
1) "user"
2) "user:1"
위처럼 키가 생성된것을 알 수 있다. 위에서 해시로 저장할 RedisUser 객체를 생성할 때 @RedisHash의 value값을 user로 줬고 id부분에 @Id 어노테이션을 붙여줬기 때문에 prefix:구분자 형태로 저장되었다.
127.0.0.1:6379> hgetall user:1
1) "_class"
2) "slido.slidoclone.health.service.RedisUser"
3) "id"
4) "1"
5) "name"
6) "hide"
Hash형태로 저장이 되므로 hgetall을 통해 값을 살펴보면 정상적으로 저장이 되었음을 확인할 수 있다.
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final UserRedisRepository userRedisRepository;
public void getUser() {
Optional<RedisUser> user = userRedisRepository.findById(1L);
System.out.println(user.get());
}
}
값을 가져올 때도 기존 Data Jpa와 마찬가지로 동일한 메소드를 사용하면 된다. 위에서는 id값을 통해 가져오기 위해 findById() 메소드를 사용했다. 해당 값을 출력시켜보면,
slido.slidoclone.health.service.RedisUser@3cf29300
정상적으로 출력됨을 확인할 수 있다.
'Coding > Java Spring' 카테고리의 다른 글
Spring Hibernate EventListener로 엔티티 변경 감지하는 방법 (18) | 2022.01.21 |
---|---|
Spring AWS SNS + SQS로 이벤트 처리하는 방법 (0) | 2022.01.18 |
Spring Interceptor를 활용하여 JWT인증 구현하기 (0) | 2022.01.03 |
Spring ApplicationEventPublisher로 이벤트 처리하는 방법 (0) | 2021.10.13 |
Java Spring Boot 전역 예외처리하는 방법 (0) | 2021.09.29 |