[Spring] 검색 처리

업데이트:

MyBatis의 동적 SQL

검색 조건이 변하면 SQL의 내용 역시 변하기 때문에 XML이나 어노테이션과 같이 고정된 문자열을 작성하는 방식으로는 제대로 처리할 수 없다.

다행히 MyBatis는 동적(Dynamic)태그 기능을 통해서 SQL을 파라미터들의 조건에 맞게 조정할 수 있는 기능을 제공한다.
MyBatis의 동적 태그는 약간의 구문을 이용해서 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어서 실행할 수 있다.



MyBatis의 동적 태그들

MyBatis는 기존의 iBatis에서 발전하면서 복잡했던 동적 SQL을 작성하는 태그들이 많이 정리되어서 다음과 같이 몇 가지의 태그들만을 이용한다.

  • if
  • choose(when, otherwise)
  • trim(where, set)
  • foreach



<if>

if는 test라는 속성과 함께 특정한 조건이 true가 되었을 때 포함된 SQL을 사용하고자 할 때 작성한다.
예를 들어, 단일 항목으로 제목(title), 내용(content), 작성자(writer)에 대해서 검색해야 하는 상황일 때

  • 검색 조건이 ‘T’면 제목이 키워드인 항목을 검색
  • 검색 조건이 ‘C’면 내용이 키워드인 항목을 검색
  • 검색 조건이 ‘W’면 작성자가 키워드인 항목을 검색


위와 같은 경우 MyBatis에서는 XML에서 다음과 같이 작성할 수 있다.

<if test="type == 'T'.tostring()">
    (title like '%'||#{keywork}||'%')
</if>
<if test="type == 'C'.tostring()">
    (content like '%'||#{keywork}||'%')
</if>
<if test="type == 'W'.tostring()">
    (writer like '%'||#{keywork}||'%')
</if>


If안에 들어가는 표현식은 OGNL표현식이라는 것을 이용한다.




<choose>

if와 달리 choose는 여러 상황들 중 하나의 상황에서만 동작한다.

<choose>
<when test="type=='T'.tostring()">
    (title like '%'||#{keyword}||'%')
</when>
<when test="type=='C'.tostring()">
    (content like '%'||#{keyword}||'%')
</when>
<when test="type=='W'.tostring()">
    (writer like '%'||#{keyword}||'%')
</when>
<otherwise>
    (title like '%'||#{keywork}||'%' OR content like '%'||#{keyword}||'%')
</otherwise>
</choose>


<otherwise>는 모든 위의 조건이 충족되지 않을 경우에 사용한다.



<trim><where><set>

trim,where,set은 단독으로 사용되지 않고 <if>, <choose>와 같은 태그들을 내포하여 SQL들을 연결해 주고, 앞 뒤에 필요한 구문들(AND,OR,WHERE 등)을 추가하거나 생략하는 역할을 한다.
SQL을 작성하다 보면 상황에 따라서 WHERE나 AND,OR등이 문제가 되는 상황이 발생할 수도 있다.
예를 들어, ‘WHERE ROWNUM <=20’은 문제가 없지만 검색 조건이 들어가면 문제가 될 수 있다.
‘WHERE title =’Text’ AND ROWNUM <=20’

만일 검색 조건이 없다면 AND라는 키워드는 들어갈 필요가 없지만, 검색 조건이 추가되면 AND가 필요한 상황이 된다.
where, trim, set은 이러한 상황에서 필요한 키워드를 붙이거나 빼는 상황에서 사용한다.

<where>의 경우 태그 안쪽에서 SQL이 생성될 때는 WHERE구문이 붙고, 그렇지 않는 경우에는 생성되지 않는다.

select * from tbl_board
    <where>
        <if test="bno != null">
            bno = #{bno}
        </if>
    </where>


위와 같은 경우 bno값이 null인 경우에는 where 구문이 없어지고, bno 값이 존재하는 경우에만 ‘where bno = xx’ 와 같이 생성된다.



<trim>은 하위에서 만들어지는 SQL문을 조사하여 앞 쪽에 추가적인 SQL을 넣을 수 있다.

select * from tbl_board
    <where>
        <if test="bno != null">
            bno = ${bno}
        </if>
        <trim prifix = "and">
        rownum =1
        </trim>
    </where>   


trim은 prifix, suffix, prefixOverrides, suffixOverrides 속성을 지정할 수 있다.

  • bno 값이 존재하는 경우
select * from tbl_board where bno =33 and rownum =1
  • bno가 null인 경우
select * from tbl_board WHERE rownum =1




foreach

foreach는 List, 배열, 맵 등을 이용해서 루프를 처리할 수 있다.
주로 IN조건에서 많이 사용하지만, 경우에 따라서는 복잡한 WHERE 조건을 만들때에도 사용할 수 있다.

예를 들어, 제목(‘T’)은 ‘TTTT’로 내용(‘C’)은 ‘CCCC’라는 값을 이용한다면 Map의 형태로 작성이 가능하다.

Map<String,String> map = new HashMap<>();
map.put("T", "TTTT");
map.put("C", "CCCC");


작성된 Map을 파라미터로 전달하고, foreach를 이용하면 다음과 같은 형식이 가능하다.

select * from tbl_board 
    <trim prefix="where ("suffix=")" prefixOverrides="OR">
        <foreach item="val" index="key" collection ="map">
            <trim prefix ="OR">
                <if test="key == 'C'.tostring()">
                    content = #{val}
                </if>
                <if test="key == 'T'.tostring()">
                    title = #{val}
                </if>
                <if test="key == 'W'.tostring()">
                    writer = #{val}
                </if>
            </trim>
        </foreach>
    </trim>


foreach를 배열이나 List를 이용하는 경우에는 item 속성만을 이용하면 되고, Map의 형태로 key와 value를 이용해야 할 때는 index와 item 속성을 둘 다 이용한다.

전달 된 값에 따라서 다음과 같이 처리된다.

select * from tbl_board
    where (content = ?
     OR title =?)




관련 서적 : 코드로 배우는 스프링 웹 프로젝트

태그:

카테고리:

업데이트:

댓글남기기