1. Redis + Spring Boot 연결
Spring Boot 에서 Spring-data-redis 라이브러리를 통해 활용해보는 방법을 알아보겠습니다.
- Redis Docker 설치 방법은 이전 포스팅을 참고 하세요!
https://lucas-owner.tistory.com/56
○ 개발 환경
- Spring Boot 2.7.10
- Redis 7.0.10
- Docker
- Mac OS Monterey 12.6
2. Spring Boot - Redis 설정
- 우선 Spring boot 에서 Redis를 사용하는 방법은 RedisRepository, RedisTemplate 2가지 방식이 존재합니다.
해당 사용방법은 설정 이후 자세하게 기술하겠습니다.
- Java에서 Redis 를 사용하기 위한 Client에는 2가지가 존재한다.
1. Lettuce
2. Jedis
Jedis 를 주로 사용했었지만, 최근에는 Lettuce를 사용한다.
-Jedis : 단점(멀티 스레드 환경 불안정, Pool 한계 등등)
- Lettuce : 사용이유(Netty 기반 환경이라 비동기 지원, Jedis 보다 빠른 속도, 안정성)
* 해당 글에서는 Lettuce를 사용하여 기술됩니다.
2-1. 라이브러리 추가
- build.gradle 에 아래의 라이브러리를 추가 후 빌드.
implementation 'org.springframework.boot:spring-boot-starter-data-redis' //redis
2-2. yml 설정
spring:
redis:
host: localhost
port: 6379
- yml 파일에 위의 설정을 추가.
- docker로 실행중이어도 local <-> Docker(Redis) 포트가 연결되어있음.
2-3. RedisConfig - 공통 설정 파일
- redis를 스프링부트에서 사용하기 위해서는 아래의 공통 파일을 생성 해주어야 한다.
- 해당 설정은 Redis 저장소와 연결하는 과정이다.
package com.boot.redis.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.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/************
* @info : Redis Repository Config 클래스
* @name : RedisRepositoryConfig
* @version : 1.0.0
* @Description : Lettuce 사용(비동기 요청 처리), RedisRepository 방식.
************/
@Configuration
@RequiredArgsConstructor
@EnableRedisRepositories
public class RedisRepositoryConfig {
private final RedisProperties redisProperties;
// lettuce
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}
// Redis template
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory()); //connection
redisTemplate.setKeySerializer(new StringRedisSerializer()); // key
redisTemplate.setValueSerializer(new StringRedisSerializer()); // value
return redisTemplate;
}
}
- key, value Serializer 설정하는 이유는 RedisTemplate를 사용 한다면, 스프링과 redis 사이에 데이터의 직렬화, 역직렬화 방식이 JDK 직렬화 방식이기 때문이다. 동작에는 전혀 영향이 있지않다, 하지만 redis-cli 를 통해 직접 데이터를 조회할때 데이터 형식을 사람이 알아볼 수 없는 형태로 출력되기 때문에 해당 설정을 적용해주어야 하는것이다.
3. RedisRepository
- JPA 를 사용을 해보았다면, 아주 쉽게 이해 할 수 있다(구조가 Spring Data JPA 와 비슷하다.)
- 객체를 담아서 저장한다.
- 트랜잭션을 지원하지 않는다.
3-1. Entity
@RedisHash("user") // options: timeToLive = 10
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
private String id; // userId: 입력안하면 임의의 값 생성됨.
private String name;
private String major; // 전공: back, front
private int age;
//private List<String> skils; // List 필요시
}
- @RedisHash 내부에 timeToLive = {seconds} 기입시 해당 데이터의 만료시간을 설정 할 수 있다.
기본값은 만료시간이 없는 -1L 이다.
- @Id 가 붙은 필드가 redis 키값이 된다 -> user:{key값}
3-2. Controller
/************
* @info : Redis User Controller
* @name : UserController
* @version : 1.0.0
* @Description :
************/
@RestController
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserSerivce serivce;
/**
* @info : Redis에 User 정보를 저장한다.
* @name : addUser
* @version : 1.0.0
*/
@PostMapping("/redis/v1/post")
public User addUser(@RequestBody User user) {
log.info("Controller Request: {}", user);
User result = serivce.addUser(user);
log.info("Controller result: {}", result);
return result;
}// save
/**
* @info : Redis에 ID 값으로 유저 정보를 가져온다.
* @name : getUser
* @version : 1.0.0
* @Description :
*/
@GetMapping("/redis/v1/getUser")
public User getUser(@RequestParam String reqId) {
User userById = serivce.getUserById(reqId);
return userById;
}
3-3. Service
**********
* @info : Redis - User Service
* @name : UserSerivce
* @version : 1.0.0
* @Description :
************/
@Service
@RequiredArgsConstructor
@Slf4j
public class UserSerivce {
private final UserRedisRepositroy repository;
/**
* @info : Redis - save (User)
* @name : addUser
* @version : 1.0.0
* @Description :
*/
@Transactional
public User addUser(User user) {
// save
User save = repository.save(user);
// find
Optional<User> result = repository.findById(save.getId());
// Handling
// 해당 data 존재시 return.
if(result.isPresent()) {
return result.get();
}else {throw new RuntimeException("Database has no Data");}
}//save
/**
* @info : Redis - get
* @name : name
* @version : 1.0.0
* @Description :
*/
@Transactional(readOnly = true)
public User getUserById(String reqId) {
Optional<User> result = repository.findById(reqId);
// Handling
if(result.isPresent()) {
return result.get();
}else {throw new RuntimeException("Database has no Data");}
}
- 저장시 save(), 조회시 findById() 를 사용한다. = JPA 와 같음.
- 삭제시 delete() 사용한다.
- 저장시 필드의 Id값을 지정하지 않으면, 랜덤한 키값이 생성되어 들어간다.
3-4.Repository
- <Class, Id 데이터 타입> 으로 작성 -> Spring Data JPA 와 같음.
public interface UserRedisRepositroy extends CrudRepository<User, String> {
}
3-5. 저장 후 조회 Test
- keys * : Redis 에 저장된 모든 키를 조회한다.(운영에서는 사용하면 위험하다. 싱글스레드이기 때문에 다른작업 불가)
- hgetall user:{key} : 키값을 기준으로 키-밸류를 조회한다.
--> skils.[0] 의 경우 hash 내부에 List 를 넣었기 때문에 출력됨.
- hkeys user:{Key} : 해당 키값의 키들을 출력한다.
- hvals user:{key} : 해당 키값의 값들을 출력한다.
4. RedisTemplate
- 위의 방식은 RedisRepository 방식으로 JPA 와 같이 사용할 수 있었다.
- RedisRepository 는 객체를 담아서 저장했다면, RedisTemplate는 특정 자료구조에 값을 저장하는 방식이다.
-> 특정 Entity 뿐 아니라 개발자가 원하는 여러가지 데이터 타입을 넣을 수 있다.
- 또한 RedisRepository는 트랜잭션을 지원하지 않는다.
/************
* @info : Redis - Service Test - Template
* @name : UserSerivceTest
* @version : 1.0.0
* @Description :
************/
@SpringBootTest
class UserSerivceTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 저장 테스트
@Test
void testStrings() {
//given
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
String key = "first";
//when
valueOperations.set(key, "helloWorld!");
//then
String value = valueOperations.get(key);
Assertions.assertThat(value).isEqualTo("helloWorld!");
}
}
- 위의 테스트 코드와 같이 RedisTemplate를 주입해서 사용한다.
- 제네릭의 타입을 명시해주어야 한다 -> Redis Config 파일에서 <?,?> 로 타입을 추론 하도록 설정했기 때문이다.
(주입된 재네릭 타입과, 사용 제네릭 타입이 다르면 어차피 에러가 발생한다.)
'DB > Redis' 카테고리의 다른 글
[Redis] Spring Boot - Redis Pub, Sub 구현&응용 (3) | 2024.03.29 |
---|---|
[Redis] Redis를 이용한 임시번호 발급(OTP, 임시비밀번호, 인증문자) - Spring Boot (0) | 2024.03.23 |
[Redis] Redis - pub/sub 이란? (1) | 2023.07.16 |
[Redis] Redis란? - Docker로 간단 Redis(Local) 설치 (1) (1) | 2023.03.29 |
댓글