환경: springboot2.7.6. java11, mysql5.7
문제 상황
endDate에 23:59:59를 세팅하는 게 귀찮고 반복적이라 느껴져서 LocalTime.MAX를 사용하는 방향으로 구현하고 있었다.
private LocalDateTime endDate;
//
endDate.toLocalDate().atTime(LocalTime.MAX)
//위와 동일
endDate.withHour(23).withMinute(59).withSecond(59).withNano(999999999)
디버그 시 endDate에 23:59:59:99999.. 로 잘 들어가는 것을 확인하고 entity.save를 진행하였는데
디비에 들어가는 값은 그 다음날 00:00:00으로 들어가 있었다.
즉 2024-01-01 23:59:59.9999999.. 로 저장을 해도 디비에는 2024-01-02 00:00:00으로 들어가는 상황
원인
java단에서 오류가 아님을 확인하니 mysql 단에서 자체 처리하는 것이라는 생각이 들었다.
LocalTime.MAX는 초 이하 9자리까지 지원한다.
즉, 23:59:59.999999999 로 처리한다.
현재 해당 디비 콜롬은 아래처럼 정의되어 있다.
초 단위 미만을 지원하지 않는 datetime은 초 단위 아래 값이 오면 반올림해버린다.
하여 초 단위 보다 더 정밀한 시간 값이 필요하면 MySQL5.7에 추가된 fractional second를 이용한 datetime(6) 등을 사용해야 한다.
하지만 MySQL이 지원하는 Fractional Seconds의 최대 자릿수는 6자리고 이를 초과했기 때문에 LocalTime.MAX를 담으면 자동으로 반올림 처리된다.
https://lenditkr.github.io/MySQL/fractional-seconds-rouding-problem/
그리고 JPA/mysql-connector 내부적으로도 반올림하는 부분이 있어 시간에 민감한 데이터인 경우 LocalDateTime.now()를 사용하는 것도 문제가 될 수 있다고 한다. 이럴 땐 DB connect 시 설정에 sendFractionalSeconds=false를 추가해줘야 하는 듯.
그래서
- 날짜 저장 시 mysql의 콜롬 타입을 고려해야 하며
- LocalTime.MAX 대신 LocalTime.of(23, 59, 59) / LocalTime.of(23, 59, 59, 999_999) 등으로 써야 한다..
'개발 > java' 카테고리의 다른 글
[java] 객체 소팅 시 비교하는 법 comparable, comparator (0) | 2024.05.08 |
---|---|
[java] 멀티 스레드 동시성 관련 (0) | 2024.05.08 |
[java] LocalDateTime, ZonedDateTime, OffsetDateTime (0) | 2024.02.14 |
[java] stream.concat, stream.generate (0) | 2024.02.06 |
[JsonProperty] boolean with is (0) | 2024.01.25 |