백엔드 서버에서 시간을 저장하기 위해서 LocalDateTime에 생성시간 등을 저장했다. 이것들을 가지고 통계를 만들기 위해 데이터베이스에서 해당 값들을 가져와야 하는데 MySQL이나 H2 같은 데이터베이스에서 이런 값들을 사용하기 위한 함수들이 준비되어있다.
MySQL 과 H2에서는 각각 다음과 같은 코드들로 시간들을 가져와 사용할 수 있다.
public List<FindByDayResponse> findByDay(Long memberId){
// todo : 사용할 데이터베이스 문법으로 변경
/* mysql */
StringTemplate toDay = stringTemplate("DAYOFWEEK({0})", board.createdAt);
/* h2 */
// StringTemplate toDay = stringTemplate("DAY_OF_WEEK({0})", board.createdAt);
return queryFactory
.select(Projections.fields(FindByDayResponse.class,
toDay.when("1").then("sun")
.when("2").then("mon")
.when("3").then("tue")
.when("4").then("wed")
.when("5").then("thr")
.when("6").then("fri")
.when("7").then("sat")
.otherwise("기타").max().as("dayOfWeek"),
toDay.count().as("countDay")
))
.from(board)
.where(board.member.id.eq(memberId))
.groupBy(toDay)
.orderBy(toDay.asc())
.distinct()
.fetch();
}
그러나 다음 코드를 보면 알 수 있듯이 해당 함수들은 특정 데이터베이스에 종속적이다.
예를 들어, Date_format 함수를 사용하는 경우, MySQL과 H2는 다른 구문으로 호출해야 할 수 있다. 그러므로, 배포 서버에서는 MySQL에서 작동하며, 로컬에서는 H2에서 작동하지 않을 수 있다.
따라서 가능한 한 데이터베이스에 종속적인 함수를 사용하는 것은 좋지 않다. 대신 이것들을 QueryDSL을 사용하여 데이터베이스에 종속적이지 않은 코드로 쿼리를 생성하도록 만들 수 있다.
public List<FindByDayResponse> findByDay(Long memberId){
NumberExpression<Integer> toDay = Expressions.numberOperation(Integer.class, Ops.DateTimeOps.DAY_OF_WEEK, board.createdAt);
return queryFactory
.select(Projections.fields(FindByDayResponse.class,
toDay.when(1).then("sun")
.when(2).then("mon")
.when(3).then("tue")
.when(4).then("wed")
.when(5).then("thr")
.when(6).then("fri")
.when(7).then("sat")
.otherwise("기타").as("dayOfWeek"),
toDay.count().as("countDay")
))
.from(board)
.where(board.member.id.eq(memberId))
.groupBy(toDay)
.orderBy(toDay.asc())
.distinct()
.fetch();
}
QueryDSL에서 제공하는 표현식을 제작하는 라이브러리를 이용하여, 데이터베이스에 종속적이지 않은 코드를 만들 수 있다. 코드의 줄이 길어지거나 복잡해지는 것도 아니고 아주 단순하고 간단한 코드 한 줄로 대체가 가능하다.
오늘은 데이터베이스에서 기본제공하는 함수들과 데이터베이스에 종속적이지 않은 QueryDSL 표현식 생성으로 쿼리를 만들어 보았다. 환경의 관점에서 다음과 같은 처리는 굉장히 중요하다고 생각한다. 단순 개발 환경뿐 아니라 배포, 운영 환경까지 생각한다면 말이다.