[MySQL] API 응답과 DB의 시간대 불일치

하원·2024년 9월 30일
post-thumbnail

안녕하세요, 하원입니다.
이번에는 제가 겪었던 API 응답과 DB의 시간대 불일치 현상에 대해 소개해 보겠습니다.


문제 상황

프로젝트를 진행하면서 로컬에서 API를 개발하고, 포스트맨으로 원하는 테스트 결과가 나와야 EC2에 배포를 진행합니다. 하지만 이번에 특정 API 응답 중 하나인 paymentAt이라는 LocalDateTime 필드 값에 문제가 발생했습니다.

DB상에 존재하는 paymentAt과 API 응답으로 전달된 paymentAt이 서로 달랐습니다. DB에는 정확한 시간의 값이 저장되어 있는데, 이상하게 API 응답으로 전달된 시간의 값은 DB보다 더 과거의 시간 값이 전달되고 있는 상태였습니다.

요약

  • 로컬에서 포스트맨으로 테스트할 때는 정상적으로 현재 시간이 전송됨.
  • EC2에 배포된 API 응답에서는 DB에 저장된 시간과 다른 시간이 전송됨.
  • RDS를 생성할 때 MySQL 파라미터 그룹의 Timezone을 Asia/Seoul로 변경한 상태.

해결 시도

1. EC2 내 시간대 변경

1) 현재 EC2 내 서버 시간대 확인

timedatectl
               Local time: Sun 2024-09-29 10:44:51 UTC
           Universal time: Sun 2024-09-29 10:44:51 UTC
                 RTC time: Sun 2024-09-29 10:44:51
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

EC2 터미널에서 timedatectl 명령어를 치니 위와 같은 결과가 출력되었습니다.
Time zone이 Etc/UTC로 설정되어 있네요. Asia/Seoul로 변경해 봅시다.

2) EC2의 Time zone을 Asia/Seoul로 변경

sudo timedatectl set-timezone Asia/Seoul
               Local time: Sun 2024-09-29 19:45:33 KST
           Universal time: Sun 2024-09-29 10:45:33 UTC
                 RTC time: Sun 2024-09-29 10:45:33
                Time zone: Asia/Seoul (KST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

이제 Time zone이 Asia/Seoul로 변경되었습니다.
"이제 되겠지?!" 라고 생각하며 다시 API를 호출한 결과, 이전과 같이 DB와 다른 시간 값이 전달되었습니다..


2. 스프링 application.yml 설정

1) 이전 application.yml 파일

spring:
  datasource:
    url: jdbc:mysql://엔드포인트:3306/스키마_이름?serverTimezone=Asia/Seoul
    username: 
    password: 
    driver-class-name: com.mysql.cj.jdbc.Driver

이전에도 시간대 관련 오류가 발생해서 datasource.url 끝에 serverTimezone=Asia/Seoul을 추가해 준 적이 있습니다. 이때 분명히 해결되었던 것 같은데, 배포된 API의 응답 결과에서는 확인하지 못했나 봅니다.

저와 비슷한 시간대 일치 오류를 겪으신 분들이 많은 것 같아서 포스팅을 여러 군데 찾아본 결과, serverTimezone=Asia/Seoul만 추가하면 반영이 안 된다고 합니다.

2) 수정된 application.yml 파일

spring:
  datasource:
    url: jdbc:mysql://엔드포인트:3306/스키마_이름?useLegacyDatetimeCode=false&serverTimezone=Asia/Seoul
    username: 
    password: 
    driver-class-name: com.mysql.cj.jdbc.Driver

useLegacyDatetimeCode=false를 url에 추가해 줘야 serverTimezone=Asia/Seoul 설정이 제대로 반영된다고 합니다. 이전에는 serverTimezone=Asia/Seoul만 추가해 줘서 serverTimezone이 적용되지 않았던 것으로 보입니다.

useLegacyDatetimeCode=false를 추가해 준 결과, 이제야 API 응답으로 DB에 저장된 시간 값이 전달됨을 확인할 수 있었습니다.

useLegacyDatetimeCode

  • useLegacyDatetimeCode=false/true 옵션은 MySQL JDBC 드라이버에서 시간 처리 방식을 제어하는 설정이라고 합니다.
  • useLegacyDatetimeCode=true : true가 기본값이며, 과거의 MySQL JDBC 드라이버 시간 처리 방식이 유지됩니다.
  • useLegacyDatetimeCode=false : MySQL JDBC 드라이버가 더 최신의 시간 처리 방식을 사용합니다, false로 설정하면 serverTimezone 설정이 제대로 반영됩니다.

로컬 테스트

이제는 로컬 테스트가 통과했다고 해서 배포된 API도 정상적으로 돌아갈 것이라는 생각을 버려야겠습니다. 포스트맨에서 테스트가 성공적으로 진행되어 전혀 의심치 않고 API를 배포했는데, 역시나 로컬 환경과 배포 환경은 매우 다르다는 것을 깨달았습니다.

"코드를 잘 작성했기 때문에 오류가 발생하지 않을 것이다"라는 생각을 버리며, 로컬뿐만 아니라 배포 환경에서도 테스트를 자세하게 진행해야겠습니다..!


마무리

왜 현직 개발자분들이 테스트가 중요하다고 했는지 알 것 같다.
로컬 환경과 배포 환경은 매우 다른 것 같아서 다양한 테스트를 진행하는 게 필수적이라고 생각한다.
코드가 아닌 외부 환경에서 오류가 발생하면 찾기 까다로운 것 같다.


참고

profile
호기심 저장소

0개의 댓글