본문 바로가기
BackEnd/QueryDsl JPA

QueryDsl에서 exists과 동일한 성능을 낼 수 있는 fetchOne

by 규난 2022. 9. 27.
728x90

바로 전 글에서 유저가 모임을 생성할 때 해당 일에 00:00 ~ 23:00시 까지 유저의 일정을 불러오는 부분을 구현 했다면 이번에는 유저가 모임을 생성하려는 시간에 겹치는 일정이 있는지 없는지 체크해서 겹치는 시간이 있으면 생성을 막는 기능을 구현 하려 한다.

 

전에 만들었던 query를 사용해서 java에서 겹치는 시간이 있는지 없는지 체크를해도 되지만 따로 query를 만들어서 체크를 하기로 했다.

밑 query는 mysql에서 exists 사용 예제다.

select exists ( 
    select *
    from group_table 
    where group_id = 2 
)

하지만 QueryDsl에서는 from절이 필수이기 때문에 저렇게 사용하지 못 한다.

그래서 exists와 동일한 성능을 낼 수 있는 query를 구글링해서 찾았는데 밑에 처럼 사용하면 된다.

@Override
public boolean existsByMeeting(
        Long memberId,
        LocalDateTime startDate,
        LocalDateTime endDate,
        LocalDateTime meetingStartDate,
        LocalDateTime meetingEndDate) {
    return jpaQueryFactory
            .select(groupMeeting)
            .from(groupMeeting)
            .where(
                    inquireMeeting(memberId, startDate, endDate),
                    includeStartDate(meetingStartDate)
                            .or(includeEndDate(meetingEndDate))
                            .or(includeStartDateAndEndDate(meetingStartDate, meetingEndDate))
                            .or(overlapStartDateAndEndDate(meetingStartDate, meetingEndDate))
            )
            .fetchFirst() != null;
}

private BooleanExpression includeStartDate(LocalDateTime startDate) {
    return groupMeeting.meetingStartDate.loe(startDate)
            .and(groupMeeting.meetingEndDate.gt(startDate));
}

private BooleanExpression includeEndDate(LocalDateTime endDate) {
    return groupMeeting.meetingStartDate.lt(endDate)
            .and(groupMeeting.meetingEndDate.goe(endDate));
}

private BooleanExpression includeStartDateAndEndDate(LocalDateTime startDate, LocalDateTime endDate) {
    return groupMeeting.meetingStartDate.loe(startDate)
            .and(groupMeeting.meetingEndDate.goe(endDate));
}

private BooleanExpression overlapStartDateAndEndDate(LocalDateTime startDate, LocalDateTime endDate) {
    return groupMeeting.meetingStartDate.goe(startDate)
            .and(groupMeeting.meetingEndDate.loe(endDate));
}

fetchFirst()는 limit(1)과 동일한 기능을 한다고 한다.

where 절에 BooleanExpression을 사용하여 다중 조건을 이용해 해당일 00:00 ~ 23:00 사이의 모임을 생성하려는 시간에 겹치는 시간이 있는지 찾아서 있으면 true 없으면 false를 반환한다. 반환 된 값을 service layer에서 받아 true일 경우 모임을 생성 못 하게 막는 방법을 선택하였다.

 

유저3의 9월 27일의 일정 중 23:00 ~ 28일 00:00의 일정이 있는데 그 시간에 모임을 생성 할 경우 예상대로 query도 잘 나가고 예외도 잘 터진다.

select
    groupmeeti0_.group_meeting_id as group_me1_9_,
    groupmeeti0_.created_at as created_2_9_,
    groupmeeti0_.updated_at as updated_3_9_,
    groupmeeti0_.content as content4_9_,
    groupmeeti0_.deleted_at as deleted_5_9_,
    groupmeeti0_.deleted_yn as deleted_6_9_,
    groupmeeti0_.group_id as group_i12_9_,
    groupmeeti0_.location as location7_9_,
    groupmeeti0_.max_participant as max_part8_9_,
    groupmeeti0_.meeting_end_date as meeting_9_9_,
    groupmeeti0_.meeting_start_date as meeting10_9_,
    groupmeeti0_.member_id as member_13_9_,
    groupmeeti0_.title as title11_9_ 
from
    group_meeting groupmeeti0_ 
where
    (
        groupmeeti0_.group_meeting_id in (
            select
                groupmeeti1_.group_meeting_id 
            from
                group_meeting_participant groupmeeti1_ 
            inner join
                member member2_ 
                    on groupmeeti1_.member_id=member2_.member_id 
            where
                groupmeeti1_.member_id=? 
                and (
                    groupmeeti0_.meeting_start_date between ? and ?
                )
        )
    ) 
    and (
        groupmeeti0_.meeting_start_date<=? 
        and groupmeeti0_.meeting_end_date>? 
        or groupmeeti0_.meeting_start_date<? 
        and groupmeeti0_.meeting_end_date>=? 
        or groupmeeti0_.meeting_start_date<=? 
        and groupmeeti0_.meeting_end_date>=? 
        or groupmeeti0_.meeting_start_date>=? 
        and groupmeeti0_.meeting_end_date<=?
    ) limit ?

 

728x90

'BackEnd > QueryDsl JPA' 카테고리의 다른 글

QueryDsl에서 MySQL Function 사용하기  (1) 2022.09.27