Docker에 Redis server를 구성한 환경이다.
Redis 및 Docker에 대한 개념은 아래 포스팅을 참고하기 바란다.
- Docker 설치 (Window 환경) 및 명령어 정리
docker pull redis
docker run --name redis_server -it -d -p 6379:6379 redis
-name : 컨테이너 이름을 redis_server로 한다.
-i : 표준입력(stdin) 활성화
-t : 키보드를 통해 표준 입력(stdin)을 전달할 수 있게 한다.
-d : 컨테이너를 백그라운드로 실행.
-p : 호스트와 컨테이너의 포트를 연결
생성한 컨테이너를 재실행
docker restart redis_server
Docker Desktop이나 명령어로 실행을 확인한다.
docker logs -f redis_server
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
host: localhost
port: 6379
@Configuration
@RequiredArgsConstructor
public class RedisConfiguration {
private final RedisProperties redisProperties;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
//redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
Redis 서버에 대한 연결을 생성하고 관리하는 역할을 하는 인터페이스로 애플리케이션이 Redis와 상호작용할 수 있게 한다.
LettuceConnectionFactory
Lettuce 클라이언트를 사용하여 Redis 연결을 관리한다. 비동기 및 멀티스레드 환경에서 사용하기 좋다.
spring boot 2부터는 Lettuce가 기본설정이다.
JedisConnectionFactory
Jedis 클라이언트를 사용하여 Redis 연결을 관리한다. 단일 스레드 환경에서 주로 사용되며, 비교적 단순한 Redis 사용 사례에 적합.
RedisTemplate는 Redis에 명령어를 실행하는 기능을 제공하는 클래스이다.
RedisTemplate를 사용할 때 Spring <-> Redis 간 데이터 직렬화 설정에 따라 Redis에 저장되는 방식이 달라진다.
트랜잭션 지원 활성화
redisTemplate.setEnableTransactionSupport(true);
1) Redis에 저장할 자료구조 객체
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@RedisHash(value = "refreshToken", timeToLive = 60)
public class RedisRefreshToken {
@Id
private Long userId;
private String token;
}
@RedisHash
@Id
2) Repository생성
public interface RedisRefreshTokenRepository extends CrudRepository<RedisRefreshToken, Long>{
}
3) 테스트
@RequestMapping("/devlog/redis")
@RestController
@RequiredArgsConstructor
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public class RedisTestController {
private final RedisRefreshTokenRepository redisRefreshTokenRepository;
@GetMapping("/saveRefreshToken")
public ResponseEntity<RedisRefreshToken> saveRefreshToken(Long userId) {
RedisRefreshToken redisRefreshToken = new RedisRefreshToken();
redisRefreshToken.setUserId(userId);
redisRefreshToken.setToken(UUID.randomUUID().toString());
redisRefreshTokenRepository.save(redisRefreshToken);
redisRefreshToken = redisRefreshTokenRepository.findById(userId).get();
return new ResponseEntity<>(redisRefreshToken, HttpStatus.OK);
}
}
4) redis-cli로 데이터 확인
docker exec -it redis_server redis-cli
timeToLive를 60초로 설정하였기 때문에 60초가 지난 후 다시 key를 조회해 보면 조회되지 않는 것을 확인할 수 있다.
String
@GetMapping("/redisTemplate-String-Save")
public void opsForValueSave(String key, String value) throws Exception {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 저장
valueOperations.set(key, value, 60, TimeUnit.SECONDS);
}
@GetMapping("/redisTemplate-String-Search")
public ResponseEntity<String> opsForValueSearch(String key, String value) throws Exception {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 조회
String result = (String) valueOperations.get(key);
return new ResponseEntity<>(result, HttpStatus.OK);
}
List
@GetMapping("/redisTemplate-List-Save")
public void opsForListSave(String key, Long value) throws Exception {
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
//저장
for(int saveValue = 1 ; saveValue <= value ; saveValue++) {
if(saveValue % 2 == 0) {
listOperations.leftPush(key, String.valueOf(saveValue));
}else {
listOperations.rightPush(key, String.valueOf(saveValue));
}
}
//만료시간 설정
listOperations.getOperations().expire(key, 60, TimeUnit.SECONDS);
}
@GetMapping("/redisTemplate-List-Pop")
public ResponseEntity<List<Object>> opsForListSearch(String key) throws Exception {
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
//List Size
long listsize = listOperations.size(key);
//조회
List<Object> list = listOperations.range(key, 0, listsize);
for(int nIdx = 0; nIdx < listsize ; nIdx++) {
//Pop
listOperations.leftPop(key);
}
return new ResponseEntity<>(list, HttpStatus.OK);
}
Set
@GetMapping("/redisTemplate-Set-Save")
public void opsForSetSave(String key, String value) throws Exception {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
//저장
setOperations.add(key, value);
//만료시간 설정
setOperations.getOperations().expire(key, 60, TimeUnit.SECONDS);
}
@GetMapping("/redisTemplate-Set-Search")
public ResponseEntity<Set<String>> opsForSetSearch(String key) throws Exception {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
//조회
Set<String> result = setOperations.members(key).stream().map(data -> (String) data).collect(Collectors.toSet());
return new ResponseEntity<>(result, HttpStatus.OK);
}
4) Hash
@GetMapping("/redisTemplate-Hash-Save")
public void opsForHashSave(String key, String mapKey, String mapValue) throws Exception {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
//저장
hashOperations.put(key, mapKey, mapValue);
//만료시간 설정
hashOperations.getOperations().expire(key, 60, TimeUnit.SECONDS);
}
@GetMapping("/redisTemplate-Hash-Search")
public ResponseEntity<Map<Object, Object>> opsForHashSearch(String key) throws Exception {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
//조회
Map<Object, Object> resultMap = hashOperations.entries(key);
return new ResponseEntity<>(resultMap, HttpStatus.OK);
}
[SpringBoot, Redis] 캐시 설정 (@Cacheable, @CachePut, @CacheEvict) (2) | 2024.09.05 |
---|
댓글 영역