[MyBatis] 쿼리문을 재사용하는 방법(sql, include)

native 쿼리를 직접 작성하는 JDBCTemplate이나 MyBatis 같은 기술은 항상 쿼리문을 직접 관리해야한다는 안좋은 단점이 있다.

물론 특정 DBMS에 맞는 native Query를 직접 작성하는 이점으로 각 쿼리마다 최적화할 수 있다는 장점이 있지만 한두개정도이지 임계점이 넘어가게되면 부담이 될 수밖에 없다.

 

그 중에서 중복으로 사용되는 조건이나 복잡한 다이나믹 쿼리 조건이 여러 쿼리에서 동시에 사용해야될 경우 xml 쿼리 파일의 용량은 그 배수만큼 커질 것이다. (예를 들어, 페이징의 경우 where절 로직은 메인 Select 문과 count 문의 조건이 limit offset을 제외하고 동일해야한다.)

 

뭐 예를 들면, 아래와 같다.

 

다방에서 매물 목록을 조회하는 페이징 API를 호출한다면.

SELECT
	*
FROM room
WHERE type = #{type}
    AND deal_type = #{deal_type}
    AND status = #{status}
LIMIT #{limit}
OFFSET #{offset}

 

위와 같은 목록쿼리가 있을 때!

 

아래와 같은 카운트 쿼리가 동시에 발생해야 기본적으로 페이징처리가 가능하다.

(여러 페이징 기법이 있지만 가장 기본적인 형태임 -> Postgresql 사용)

SELECT
	count(*)
FROM room
WHERE type = #{type}
    AND deal_type = #{deal_type}
    AND status = #{status}

 

이때 where절 이후부터 status 조건까지의 쿼리 조각이 다른 부분에서도 활용하게 된다면 중복적으로 쿼리문이 작성되게 된다.

 

이런 중복 쿼리조각을 하나의 조각으로 관리할 수 있다.

 


<sql> 태그를 활용한 쿼리 조각화

우선 XML 문서에 아래와 같이 선언되어 있을 것이다.

<select id = "selectRooms" resultType = "room">
	SELECT
        *
    FROM room
    WHERE type = #{type}
        AND deal_type = #{deal_type}
        AND status = #{status}
    LIMIT #{limit}
    OFFSET #{offset}
</select>

<select id = "countRooms" resultType = "Integer">
    SELECT
        count(*)
    FROM room
    WHERE type = #{type}
        AND deal_type = #{deal_type}
        AND status = #{status}
</select>

 

현재는 중복된 상태이나 <sql> 태그를 이용해서 이를 관리하는 형태로 변경해보겠습니다.

<select id = "selectRooms" resultType = "room">
	SELECT
        *
    FROM room
    <include refid = "roomsCondition"/>
    LIMIT #{limit}
    OFFSET #{offset}
</select>

<select id = "countRooms" resultType = "Integer">
    SELECT
        count(*)
    FROM room
	<include refid = "roomsCondition"/>
</select>

<sql id = "roomsCondition">
	WHERE type = #{type}
    	AND deal_type = #{deal_type}
        AND status = #{status}
</sql>

이런식으로 쿼리문을 관리할 수 있게된다.

 

지금은 예제이므로 그닥 많은 차이를 느끼지는 못하겠지만 3개 이상이 되었을때는 쿼리 자체가 매우 깔끔해보이고 정리된 모습을 보여줄 수 있을 것이다.

댓글

Designed by JB FACTORY