기본 Spring Boot 프로젝트 세팅
- Spring Boot는 3.xx 버전
- MySQL 8.x 버전
- JDK 17
application.yml
# local 환경
spring:
profiles:
default: local
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
Board 엔티티 만들기
@Entity
@Table(name = "boards")
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
@CreatedDate
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime createdAt;
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
}
기본 Controller, Service, Repository 만들기
@RestController
@RequestMapping("boards")
public class BoardController {
private BoardService boardService;
public BoardController(BoardService boardService) {
this.boardService = boardService;
}
@GetMapping()
public List<Board> getBoards(
@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size
) {
return boardService.getBoards(page, size);
}
}
@Service
public class BoardService {
private BoardRepository boardRepository;
public BoardService(BoardRepository boardRepository) {
this.boardRepository = boardRepository;
}
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
public interface BoardRepository extends JpaRepository<Board, Long> {
Page<Board> findAllByOrderByCreatedAtDesc(Pageable pageable);
}
더미 데이터 넣기
-- 높은 재귀(반복) 횟수를 허용하도록 설정
-- (아래에서 생성할 더미 데이터의 개수와 맞춰서 작성하면 된다.)
SET SESSION cte_max_recursion_depth = 1000000;
-- boards 테이블에 더미 데이터 삽입
INSERT INTO boards (title, content, created_at)
WITH RECURSIVE cte (n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM cte WHERE n < 1000000 -- 생성하고 싶은 더미 데이터의 개수
)
SELECT
CONCAT('Title', LPAD(n, 7, '0')) AS title, -- 'Title' 다음에 7자리 숫자로 구성된 제목 생성
CONCAT('Content', LPAD(n, 7, '0')) AS content, -- 'Content' 다음에 7자리 숫자로 구성된 내용 생성
TIMESTAMP(DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 3650 + 1) DAY) + INTERVAL FLOOR(RAND() * 86400) SECOND) AS created_at -- 최근 10년 내의 임의의 날짜와 시간 생성
FROM cte;
Spring Boot 프로젝트에 Redis 세팅
build.gradle 의존성 추가
...
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
application.yml
# local 환경
spring:
profiles:
default: local
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
data:
redis:
host: localhost
port: 6379
logging:
level:
org.springframework.cache: trace # Redis 사용에 대한 로그가 조회되도록 설정
Redis 설정 추가
config/RedisConfig
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
// Lettuce라는 라이브러리를 활용해 Redis 연결을 관리하는 객체를 생성하고
// Redis 서버에 대한 정보(host, port)를 설정한다.
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
}
}
config/RedisCacheConfig
@Configuration
@EnableCaching // Spring Boot의 캐싱 설정을 활성화
public class RedisCacheConfig {
@Bean
public CacheManager boardCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
// Redis에 Key를 저장할 때 String으로 직렬화(변환)해서 저장
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
// Redis에 Value를 저장할 때 Json으로 직렬화(변환)해서 저장
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new Jackson2JsonRedisSerializer<Object>(Object.class)
)
)
// 데이터의 만료기간(TTL) 설정
.entryTtl(Duration.ofMinutes(1L));
return RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
BoardService에 캐싱 로직 추가
@Service
public class BoardService {
private BoardRepository boardRepository;
private Pageable pageable;
public BoardService(BoardRepository boardRepository) {
this.boardRepository = boardRepository;
}
@Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager")
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
- cacheNames : 캐시 이름을 설정
- key : Redis에 저장할 Key의 이름을 설정
- cacheManager : 사용할 cacheManager의 Bean 이름을 지정
API 실행해보기
Redis-cli를 활용해 정상적으로 캐싱이 됐는 지 확인
$ redis-cli
$ keys * # Redis에 저장되어 있는 모든 key 조회
$ get getBoards::boards:page:1:size:10 # 특정 key의 Value 조회
$ ttl getBoards::boards:page:1:size:10 # 특정 key의 TTL 조회
'개발이 좋아서 > Redis가 좋아서' 카테고리의 다른 글
Docker Compose로 Redis + Spring Boot 띄우기 (0) | 2025.01.31 |
---|---|
부하 테스트를 통해 Redis 적용 전 후 성능 비교하기 (1) | 2025.01.31 |
AWS EC2에서 Redis 활용하기 (0) | 2025.01.31 |
Redis 캐싱 전략 (0) | 2025.01.28 |
Redis란? (1) | 2025.01.28 |