티스토리 뷰
개발을 하면서 그날의 끝 시간 관련해서 제대로 동작하지 않는 문제가 있었다.
Member 테이블이 아래와 같이 있고, 특정 날짜 이전에 생성된 Member 리스트를 구하고 싶다는 요구사항이 왔다고 가정해 보자. (DB는 당연하게도 PostgreSQL이다)
id | name | created_at |
1 | 홍길동 | 2023-11-24 00:00:00.000000 |
2 | 김길동 | 2023-11-23 23:59:59.000000 |
3 | 이길동 | 2023-11-23 00:00:00.000000 |
특정 날짜 이전에 생성된 Member 리스트를 구하기 위한 코드는 아래와 같이 작성했다.
//MemberRepository.java
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByCreatedAtLessThanEqual(LocalDateTime dateTime);
}
//TempService.java
public class TempService {
private final MemberRepository memberRepository;
public List<Member> getMember(LocalDate lastDate) {
LocalDateTime calculatedDateTime = LocalDateTime.of(lastDate.getYear(), lastDate.getMonth(),
lastDate.getDayOfMonth(), 0, 0, 0).minusNanos(1); //현재날짜 보다 이전에 생성된 데이터들을 구하기 위해 minusNanos(1)을 해줬다.
return memberRepository.findByCreatedAtLessThanEqual(calculatedDateTime);
}
}
맞다. LessTahnEqual이 아니라 Before을 해주면 되지만 문제상황을 알기 위해서 일단 LessTahnEqual을 사용했다고 가정해 보겠다.
위의 코드의 TeamService::getMember(LocalDate.of(2023, 11, 24))를 호출하면 결과 값이 pk id = 2, 3번인 Member 2개가 리턴될 거라고 예상할 수 있지만 실제 리턴값은 1, 2, 3번의 Member 모두가 리턴된다.
이유를 찾을 수 없어서 열심히 알아보던 중 강남언니의 블로그에서 비슷한 증상을 겪은 글을 보게 됐다.(https://blog.gangnamunni.com/post/mysql-endtime-timestamp/)
위의 글을 보고 PostgreSQL의 timestamp 타입과 관련이 있을 수도 있다고 생각했고 관련된 정보를 찾았다!
PostgreSQL의 공식문서에서 timestamp 타입에 대한 설명이 나오는데 microsecond까지만 지원이 된다고 나와있다. 하지만 우리의 코드에서는 그보다 더 정교한 타입인 nanosecond를 -1 해서 원하는 대로 동작이 되지 않았던 것이다.
따라서 아래와 같이 minusNanos(1)이 아닌 minusNanos(1000)을 했더니 원하던 대로 정상 동작하는 것을 볼 수 있었다.
//MemberRepository.java
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByCreatedAtLessThanEqual(LocalDateTime dateTime);
}
//TempService.java
public class TempService {
private final MemberRepository memberRepository;
public List<Member> getMember(LocalDate lastDate) {
LocalDateTime calculatedDateTime = LocalDateTime.of(lastDate.getYear(), lastDate.getMonth(),
lastDate.getDayOfMonth(), 0, 0, 0).minusNanos(1000); //현재날짜 보다 이전에 생성된 데이터들을 구하기 위해 minusNanos(1)을 해줬다.
return memberRepository.findByCreatedAtLessThanEqual(calculatedDateTime);
}
}
DB의 타입에 대해서 무신경하게 개발하고 있었던 것 같아서 반성하는 계기가 됐다.
ref
- Total
- Today
- Yesterday