본문 바로가기

Spring

Redis와 JPA를 활용한 Spring Cache 구현: 성능 최적화의 시작!

728x90
반응형

애플리케이션의 성능을 최적화하는 가장 강력한 방법 중 하나는 캐싱(Caching)입니다. 캐시를 통해 빈번한 데이터베이스 접근을 줄이고 응답 시간을 획기적으로 단축할 수 있습니다. 이번 글에서는 Spring Cache를 활용해 Redis와 JPA를 함께 사용하는 방법을 소개하고, 간단한 예제를 통해 그 흐름을 쉽게 이해할 수 있도록 설명드리겠습니다.

Spring Cache와 Redis란?

  • Spring Cache: Spring에서 제공하는 캐싱 추상화 기능으로, 다양한 캐시 스토리지를 사용할 수 있습니다. 이는 애플리케이션 코드에 최소한의 변경으로 캐시 기능을 추가할 수 있게 해줍니다.
  • Redis: Redis는 인메모리 데이터 구조 스토리지로, 빠른 읽기/쓰기 성능을 제공합니다. Spring Cache와 함께 사용하면, 데이터베이스 접근 횟수를 크게 줄일 수 있습니다.
  •  
반응형

프로젝트 설정

먼저, Gradle 혹은 Maven 프로젝트에서 Redis와 Spring Data JPA를 설정해야 합니다.

Gradle 의존성 설정

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-cache'
    implementation 'com.h2database:h2' // 테스트용 H2 데이터베이스
}

Spring Cache와 Redis 설정

이제 Spring Cache와 Redis 설정을 추가해보겠습니다. application.yml 파일에서 Redis 연결 정보를 설정합니다.

spring:
  cache:
    type: redis
  redis:
    host: localhost
    port: 6379

그리고 캐시를 활성화하기 위해 @EnableCaching 어노테이션을 메인 클래스에 추가합니다.

@SpringBootApplication
@EnableCaching
public class CacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheApplication.class, args);
    }
}

JPA 엔티티와 레포지토리 구현

예제를 위해 간단한 User 엔티티와 JPA 레포지토리를 만들어 보겠습니다.

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    // Getters and Setters
}
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByName(String name);
}

캐시 적용하기

UserService에서 캐시를 적용해봅시다. @Cacheable 어노테이션을 사용해 데이터베이스 조회 결과를 캐시에 저장하고, 같은 요청이 들어오면 캐시에서 데이터를 가져오도록 합니다.

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Cacheable(value = "users", key = "#name")
    public User getUserByName(String name) {
        return userRepository.findByName(name).orElseThrow(() -> new RuntimeException("User not found"));
    }

    @CacheEvict(value = "users", key = "#user.name")
    public User saveUser(User user) {
        return userRepository.save(user);
    }
}
  • @Cacheable: 해당 메소드의 결과를 캐시에 저장합니다. 이후 동일한 인풋이 들어올 경우 메소드를 실행하지 않고 캐시에서 결과를 반환합니다.
  • @CacheEvict: 데이터를 저장하거나 업데이트할 때, 해당 키에 대한 캐시를 삭제합니다.

7. 데이터 흐름 이해하기

캐시를 사용하지 않는 경우, 애플리케이션은 사용자의 요청을 받을 때마다 데이터베이스에 접근하여 데이터를 조회합니다. 하지만 캐시를 도입하면 다음과 같은 흐름으로 동작하게 됩니다:

  1. 첫 번째 요청: 사용자가 특정 이름으로 getUserByName 메소드를 호출하면, 메소드는 캐시에서 데이터를 찾습니다. 캐시에 데이터가 없으면 데이터베이스에서 데이터를 가져오고, 그 결과를 캐시에 저장합니다.
  2. 두 번째 이후 요청: 동일한 이름으로 getUserByName을 호출하면, 데이터베이스에 접근하지 않고 캐시에서 데이터를 반환합니다.
  3. 데이터 변경 시: 새로운 사용자를 저장하거나 기존 사용자를 업데이트할 때, saveUser 메소드가 호출됩니다. 이때 캐시에 저장된 해당 사용자의 데이터를 제거하여 이후에 새로운 데이터를 다시 캐싱하게 됩니다.
728x90

이제 Redis와 JPA를 활용하여 Spring Cache를 구현하는 방법을 이해하셨을 것입니다. 캐시는 성능 최적화를 위해 필수적인 도구이며, Redis와 같은 빠른 인메모리 스토리지를 활용하면 애플리케이션의 응답성을 크게 개선할 수 있습니다. 이번 글을 통해 캐시 적용의 기본 개념을 익히고, 실전 프로젝트에 적용해 보시기 바랍니다.

728x90
반응형