Backend/SpringBoot

Main DB (Postgresql) + Cache (Redis) 사용하기

Dean83 2025. 9. 3. 15:07

소규모의 경우에는 이렇게 하지 않아도 될 수 있으나, 데이터가 많고 읽는 경우가 많을때 이 방식을 많이 쓴다. 

메인DB로 Postgresql 을 사용하는 이유는 성능도 좋지만 무료이고, 검증되었기 때문이라고 본다. 

SpringBoot 설정에서 캐시 설정을 Redis로 해 놓으면 캐시에서 조회하는것도, 캐시를 갱신하는것도 다 자동으로 해 준다.

1. Gradle 추가

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.postgresql:postgresql'

 

2. yaml 설정

  • db 접속 정보는 대부분 env 파일로 따로 빼 낸 다음 불러오거나 AWS를 이용하므로 참고. (https://dean83.tistory.com/322 여기 하단부 참고)
spring:
  application:
    name: 이름
    
  datasource:
    url: jdbc:postgresql://localhost:5432/테이블명
    username: 유저명
    password: 비밀번호
    driver-class-name: org.postgresql.Driver

  jpa:
    hibernate:
      ddl-auto: none   # 운영 환경에서는 validate 또는 none 권장
    show-sql: true        # 실행되는 SQL 출력. product 에서는 false
    properties:
      hibernate:
        format_sql: true   # SQL 보기 좋게 정렬
        highlight_sql: true # (Hibernate 5.5+) ANSI 색상 강조
        use_sql_comments: true # JPQL -> SQL 변환 시 주석 추가
        # 사용할 데이터베이스 방언(Dialect) 지정
        dialect: org.hibernate.dialect.PostgreSQLDialect
    database-platform: org.hibernate.dialect.PostgreSQLDialect
    open-in-view: false   # OSIV 비활성화 (서비스 계층에서만 영속성 사용)

  sql:
    init:
      mode: never   # schema.sql, data.sql 실행 여부 (never, embedded, always)
  #  defer-datasource-initialization: true
  #  ↑ JPA가 스키마 생성 후 data.sql 실행하도록 보장 (Spring Boot 2.5+)
  
  logging:
  level:
    root: DEBUG
    org.hibernate.SQL: DEBUG            # 실행되는 SQL 로그
    org.hibernate.type.descriptor.sql: TRACE  # SQL에 바인딩되는 파라미터 값 출력

 

3. Redis Cache 커스텀 설정

  • 굳이 커스텀 설정을 하지 않아도 가능한데, 캐시 시간 변경이나, json serialize를 할 경우 설정을 변경해야 한다.
@Configuration
@EnableCaching  // 캐시 기능 활성화
public class RedisConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(5))   // 캐시 TTL: 5분
                .serializeValuesWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(
                                new GenericJackson2JsonRedisSerializer()
                        )
                );

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

 

4. 활용 예

//엔티티
@Entity
@Table(name = "users")
@Getter @Setter
@NoArgsConstructor @AllArgsConstructor
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

....

//리파지토리
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

...
//서비스
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    @Cacheable(value = "userCache", key = "#id")
    public User getUser(Long id) {
        // Redis에 캐시가 없을 때만 DB 조회
        System.out.println("DB 조회 발생 for id=" + id);
        return userRepository.findById(id).orElseThrow();
    }

    @CacheEvict(value = "userCache", key = "#user.id")
    public User updateUser(User user) {
        // DB 갱신 + 캐시 무효화
        return userRepository.save(user);
    }
}

...

//컨트롤러
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        return userService.updateUser(user);
    }
}
  • 개발자가 따로 뭘 하지 않아도 서비스의 메서드가 호출될 때 @Cachable 로 인해 자동으로 캐시에서 내용을 찾고, 없을경우만 쿼리 조회 한다.
  • 캐시 갱신 등 관리도 자동으로 한다.
  • 쓰기 작업을 할때 @CacheEvict (해당 캐시 키 삭제) 를 반드시 해야한다. 내용이 변경되었기 때문에 무효화를 해주어야 한다.
    • 혹은 @CachePut (value = "userCache", key = "#user.id") 를 통해 갱신을 해 주어야 한다.