본문 바로가기
Web Development/ETC

[MyBatis] MyBatis 를 활용한 동적 쿼리

by graycode 2022. 6. 28.

필터링 기능 구현 시 다중 값을 쿼리하거나 특정 값 선택 여부에 따라 동적 쿼리로 구현해야 하는 경우,

우선 MyBatis 에 넘길 객체의 요소를 아래와 같이 설정한다.

@Data
@Alias("clothes")
public class ClothesDTO {
	private String keyword;
	private String brand;
	private List<String> type;
	private int minCost;
	private int maxCost;
}

 

keyword 는 사용자가 입력한 검색어, brand 는 단일 선택 값, type 은 체크박스 다중 선택값을 List 에 담아 전달한다.

minCost, maxCost 는 검색하고자 하는 특정 값의 범위를 지정한다.

 

MyBatis 에는 다양한 동적쿼리문이 있는데 대표적으로 if 문과 foreach 문이 있고 이는 JSTL 문과 유사한 면이 있다.

 

먼저 if 문의 기본적인 구문은 아래와 같다.

<if test='param != null'>
    {query syntax}
</if>

test 에 지정된 조건문(!=, ==, <, >, equals() ... ) 에 따라 내부의 쿼리문이 작성될 지 여부를 결정한다.

 

아래는 다중 값을 쿼리하기 위한 foreach 문

<foreach item="item" index="index" collection="paramList" open="(" separator="," close=")">
	#{item}
</foreach>

 

리스트의 특정 인덱스를 지정하기 위해서 index 변수를 사용 가능하고,

open, close, separator 는 리스트가 괄호로 열고 닫히고 쉼표를 기준으로 요소를 구분한다는 의미를 가지고 있다.

 

item, collection 은 foreach 문에 대입해보면 아래와 같다.

for (String item : paramList) {
    System.out.println(item);
}

이렇게 List 의 값을 하나씩 꺼내 각각 쿼리문에 적용한다.

 

이런 방식으로 필터링할 값을 저장한 ClothesDTO 객체를 매개변수로 전달해 아래와 같이 쿼리문을 작성할 수 있다.

<select id="getList" parameterType="clothes" resultType="clothes">
    select * from clothes where brand = #{brand}
    <if test='keyword != null and !keyword.equals("")'>
        and name like '%' || #{keyword} || '%'
    </if>
    <if test='type.size != 0'>
        and type in
        <foreach item="var" index="idx" collection="type" open="(" separator="," close=")">
            #{var}
        </foreach>
    </if>
    <![CDATA[ 
    and min_cost >= #{minCost} and max_cost <= #{maxCost}
    ]]>
</select>

keyword 에 값이 null 값이 아니고 공백이 아닐 시 내부 like 쿼리문이 작성되고,

다중 선택값이 저장된 리스트의 크기가 0보다 클 경우, 즉 값이 존재할 경우 값을 하나씩 꺼내온다.

끝으로 cdata 로 쿼리문을 감싸 >=, <= 를 문자열로 인식시켜 가격 값의 범위를 지정한다.

 

위의 쿼리가 정상적으로 실행 시 실제 쿼리문은 아래와 같을 것이다.

select * from clothes where brand = polyteru
and name like '%liso%'
and type in ('pant', 'shoes')
and min_cost >= 80000 and max_cost <= 120000

댓글