redis 란?
- Remote Dictionary Server 의 약자
- 데이터를 메모리에 저장
- 메모리에 저장하기 떄문에 데이터의 빠른 읽기 및 쓰기 가능
- 큐 시스템, 세션관리, 실시간 분석 등에 사용 됨
- 조회가 많은 데이터들은 redis를 통해 캐시로 관리하면 빠른 조회가 가능
- 컴퓨터 캐시와 redis 캐시는 다른 개념이다.
- 따라서 pc의 캐시 (브라우저 캐시, 운영체제 캐시, 애플리케이션의 데이터 캐시)를 삭제한다고 해서
- redis 의 캐시가 삭제되지 않는다.
- 단, redis를 종료시키거나 데이터를 삭제하는 경우 redis 캐시가 삭제된다.,
- 따라서 운영할 애플리케이션에 적용할 경우 중요할 수 있는 redis 캐시데이터는 주기적으로
- RDB로 이관을 시켜주어야 한다.
[redis 데이터가 삭제되는 경우]
- Redis 서버를 수동으로 종료하거나 재시작한 경우 (Persistence가 설정되지 않은 상태에서)
- 특정 키를 수동으로 삭제한 경우 (DEL, FLUSHDB, FLUSHALL 명령어 사용)
- 설정된 TTL(Time-To-Live, 만료 시간)이 지나 데이터를 자동 삭제한 경우
- Redis 메모리가 부족해 LRU 정책(Least Recently Used) 등으로 데이터를 삭제한 경우
[redis 설치 : 윈도우]
설치 파일 다운로드 경로 : https://github.com/microsoftarchive/redis/releases








- C:\Program Files\Redis 이동
- redis-server.exe 실행(redis 실행)

- redis-cli.exe 실행 (redis 명령어 사용하기 실행)

- redis-cli.exe 로 redis cli 접근 가능
- PING 이라고 명령어 입력 시 'PONG' 으로 응답받은 거면
- redis 실행 중이라는 것

- INFO 입력 시 현재 실행 중인 redis 의 정보를 확인 가능

- 추후 redis의 포트 변경이나 password 설정은 'redis.windows.conf' 로 가능하다.

- 6379 대신 다른 값 넣으면 해당 포트로 사용
- ★ 포트 지정 시 이미 사용 중인 포트인지 아닌지 확인해보자


- 위 "# requiredpass foobared" 에서 # 을 지워 주석해제 하고 footbared 자리에 원하는 패스워드 입력하면
- 해당 입력 값으로 패스워드 사용 가능
- 위 같은 방식으로 (구글링 해서 더 찾아보자)
bind [허용할 ip] // 외부 접근 가능한 ip 지정
logfile [내가 지정할 파일명.log] // redis log 파일 생성 및 지정
이렇게도 사용 가능하다.
# redis-cli.exe 명령어 정리
SHUTDOWN # 종료
redis-server # redis 재실행 (단 redis-server.exe 파일이 같은 경로에 있어야 함)
[실습 프로젝트 생성]
스프링 이니셜라이저 사용 : https://start.spring.io/
- 깜빡하고 lombok 안 넣어서 build.gradle 추가 작성 진행했음;;

- build.gradle에 추가로 작성한 것
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-web'
// lombok 추가한 부분------------------------------------------------------------
implementation 'org.projectlombok:lombok' // Lombok 의존성 추가
compileOnly 'org.projectlombok:lombok' // Lombok을 컴파일 전용으로 설정
annotationProcessor 'org.projectlombok:lombok' // Lombok의 애너테이션 프로세서 설정
// ------------------------------------------------------------------------------
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
[코드]
목표 : id, userEmail, customToken 값을
id로 redis 에서 관리하게 할 것이다.
key로 사용되는 것은 id 이며 key 값은 RedisUser로 정하였다.
# applicaion.properties (redis 관련 설정)
spring.application.name=try-redis
# [redis 설정]
# redis-host
spring.data.redis.host=localhost
# redis-port
spring.data.redis.port=6379
# redis-password 없으면 비워두자
spring.data.redis.password=
# RedisConfig.java (Redis 사용을 위한 config 파일)
package com.study.try_redis.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
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;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.data.redis.password}")
private String password;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port) {{
setPassword(password);
}});
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
# RedisUser.java (redis 에 담길 데이터 객체 : 직렬화)
package com.study.try_redis;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.redis.core.RedisHash;
import java.io.Serializable;
@Getter
@NoArgsConstructor
@RedisHash("RedisUser") // key 가 RedisUser 이고 값이 아래 변수명들을 가지는 객체가 된다는 의미
public class RedisUser implements Serializable {
// redis 에서는 GeneratedValue 지원 안 해서
private String id; // key 가 될 값 // 별도 어노테이션 지원이 없어 서비스 로직 서 구분해주어야 한다.
private String userEmail; // 유저이메일
private String customToken; // 임의로 값 넣어줄 거임
@Builder
public RedisUser(String id, String userEmail, String customToken) {
this.id = id;
this.userEmail = userEmail;
this.customToken = customToken;
}
public String getId() {
return id;
}
public String getUserEmail() {
return userEmail;
}
public String getCustomToken() {
return customToken;
}
}
# RedisController.java (redis 값 crud 매핑될 uri)
- 여기 예제에서는 CR만 수행 UD 는 별도로 학습하도록 하자
package com.study.try_redis.controller;
import com.study.try_redis.RedisUser;
import com.study.try_redis.service.RedisService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/redis-api")
public class RedisController {
// service 빈 주입
private final RedisService redisService;
public RedisController(RedisService redisService) {
this.redisService = redisService;
}
@GetMapping("/getAllList")
public List<RedisUser> getAllList() {
return redisService.getAllList();
};
@GetMapping("/getRedisUserByEmail")
public RedisUser getRedisUserByEmail(@RequestParam String userEmail) {
return redisService.getRedisUserByEmail(userEmail);
}
@GetMapping("/getRedisUserById")
public RedisUser getRedisUserById(@RequestParam String id) {
return redisService.getRedisUserById(id);
};
@PostMapping("/setRedisUser")
public void setRedisUser(@RequestBody RedisUser redisUser) {
redisService.setRedisUser(redisUser);
};
}
# RedisService.java (인터페이스)
package com.study.try_redis.service;
import com.study.try_redis.RedisUser;
import java.util.List;
public interface RedisService {
public List<RedisUser> getAllList();
public RedisUser getRedisUserByEmail(String userEmail);
public RedisUser getRedisUserById(String id);
public void setRedisUser(RedisUser redisUser);
}
# RedisServiceImpl.java (구현체)
package com.study.try_redis.service;
import com.study.try_redis.RedisUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Service
public class RedisServiceImpl implements RedisService{
//빈 주입
private RedisTemplate<String, RedisUser> redisTemplate;
public RedisServiceImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* ※ 주석처리한 opsForValue는 데이터가 객체가 아닌 string 타입으로 저장될 때 사용하기 좋은 메소드이다.
* 이번 테스트에서는 객체를 직렬화하여 넣었기 떄문에 주석처리 해두었다. -> opsForHash를 사용하였다.
*/
@Override
public List<RedisUser> getAllList() {
// Set<String> keys = redisTemplate.keys("RedisUser:*");
// List<RedisUser> userList = redisTemplate.opsForValue().multiGet(new ArrayList<>(keys));
// Redis에서 "RedisUser" 해시의 모든 키 (id들)을 조회
// key 값을 먼저 가져온 후 조회
Set<String> keys = redisTemplate.opsForHash().keys("RedisUser").stream()
.map(objectKey -> (String) objectKey).collect(Collectors.toSet());
List<RedisUser> userList = redisTemplate.opsForHash().multiGet("RedisUser", new ArrayList<>(keys)).stream()
.map(objectUser -> (RedisUser) objectUser).collect(Collectors.toList());
if (userList.isEmpty()) {
throw new RuntimeException("not exsist any users");
}
return userList;
}
@Override
public RedisUser getRedisUserByEmail(String userEmail) {
// userEmail 은 id가 아니므로 전체를 조회한 후 그 중에서 찾는다.
List<RedisUser> allUsers = getAllList();
RedisUser findUser = null;
for (RedisUser targetUser : allUsers) {
if (targetUser.getUserEmail().equals(userEmail)) {
findUser = targetUser;
break;
}
}
if (findUser == null) throw new RuntimeException("not found user : " + userEmail);
return findUser;
}
@Override
public RedisUser getRedisUserById(String id) {
RedisUser findUser = null;
// findUser = redisTemplate.opsForValue().get("RedisUser:"+id);
// findUser = redisTemplate.opsForValue().get(id); // id만 키로 등록시키기로 한 경우 이렇게도 가능
findUser = (RedisUser) redisTemplate.opsForHash().get("RedisUser", id);
if (findUser == null) throw new RuntimeException("not found user by id : " + id);
return findUser;
}
@Override
public void setRedisUser(RedisUser redisUser) {
try {
// redisTemplate.opsForValue().set(redisUser.getId(), redisUser);
redisTemplate.opsForHash().put("RedisUser", redisUser.getId(), redisUser);
} catch (Exception e) {
log.error("RedisUser Set ERROR by : ");
log.error(e.getLocalizedMessage());
throw new RuntimeException("ERROR - [set RedisUser]");
}
}
}
[실행 결과]
#1 입력


#2 id (key) 값으로 조회

#3 userEmail(nonKey) 값으로 조회

#4 모든 user 조회


- 제대로 저장되고 조회된다.
- 이번에 학습한 redis의 기능들을 이용하여 애플리케이션의 ACCESS_TOKEN, REFRESH_TOKEN 과
- 관련된 기능 개발에 적용 가능하며 정책 도입에 응용할 수 있다
아래는 너무 헷갈려서 gpt를 통해 정리한 것이다
참조하자!




'개발 환경 설정 및 툴 사용법' 카테고리의 다른 글
H2 DB - setting (1) | 2024.12.08 |
---|---|
AWS EC2 에서 FTP 사용하기 (6) | 2024.10.03 |
Spring Boot with Mybatis : 스프링부트 Mybatis 설정 (요약) (0) | 2024.08.31 |
Spring Boot with Mybatis : 스프링부트 Mybatis 설정 + User CRUD (FULL 버전) (6) | 2024.08.31 |
깃허브(git) 토큰(token) 대신에 OAuth 인증으로 작업하기 with 소스트리 (0) | 2023.12.28 |