Part 15. 검색 처리

15.2 MyBatis의 동적 SQL

  • SQL문에서 느끼는 점은 검색 조건이 변하면 SQL의 내용 역시 변하기 때문에 XML이나 어노테이션과 같이 고정된 문자열을 작성하는 방식으로는 제대로 처리할 수 없다는 사실이다.
  • 다행히 MyBatis는 동적(Dynamic) 태그 기능을 통해 SQL을 파라미터들의 조건에 맞게 조정할 수 있는 기능을 제공한다.
  • MyBatis의 동적 태그는 약간의 구문을 이용해 전달되는 파라미터를 가공해 경우에 따라 다른 SQL을 만들어 실행할 수 있다.

15.2.1 MyBatis의 동적 태그들

  • MyBatis는 기존의 iBatis에서 발전하면서 복잡했던 동적 SQL을 작성하는 태그들이 많이 정리되어서 다음과 같이 몇 가지의 태그들만 이용한다.
    • if
    • choose(when,otherwise)
    • trim(where,set)
    • foreach

< if >

  • if는 test라는 속성과 함께 특정한 조건이 true가 되었을 때 포함된 SQL을 사용하고자 할 때 작성한다.
  • 예를 들어, 단일 항목으로 제목(title), 내용(content), 작성자(writer)에 대해 검색해야 하는 상황이라고 가정하면
    • 검색 조건이 'T'면 제목(title)이 키워드(keyword)인 항목을 검색
    • 검색 조건이 'C'면 내용(conetnt)가 키워드(keyword)인 항목을 검색
    • 검색 조건이 'W'면 작성자(writer)가 키워드(keywordk)인 항목을 검색
  • 위와 같은 경우 MyBatis에서는 XML에서 다음과 같이 작성할 수 있다.
<if test="type == 'T'.toString()">
	(title lilke '%'||#{keyword}||'%')
</if>
<if test="type == 'C'.toString()">
	(content like '%'||#{keyword}||'%')
</if>
<if test="type == 'W'.toString()">
	(writer like '%'||#{keyword}||'%')
</if>

< choose >

  • if와 달리 choose는 여러 상황들 중 하나의 상황에서만 동작한다.
  • Java 언어의 'if~else'나 JSTL의 < 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 '%'||#{keyword}||'%' 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'은 문제가 없지만 검색 조건이 들어가면 문제가 될 수 있다.
  • 위의 그림과 같이 만일 검색 조건이 없다면 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 prefix = "and">
        rownum = 1
        </trim>
    </where>
  • trim은 prefix, suffix, prefixOverrides, suffixOverrides 속성을 지정할 수 있다.

< 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 = ? )
    INFO : jdbc.sqlonly - select * from tbl_board where (content = 'CCCC' OR title = 'TTTT' )
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글