가희의자기개발블로그

동적SQL 본문

백엔드/myBatis

동적SQL

가희gahui 2020. 7. 4. 15:30
반응형

동적 SQL엘리먼트들을 JSTL이나 XML기반의 텍스트 프로세서를 사용해 본 사람에게는 친숙할 것이다. 마이바티스의 이전 버전에서는 알고 이해해야 할 엘리먼트가 많았다. 마이바티스의 다른 엘리먼트의 사용을 최대한 제거하기 위해 OGNL기반의 표현식을 가져왔다.

 

01_ IF

동적 SQL에서 가장 공통적으로 사용되는 것으로 where의 일부로 포함될 수 있다. 

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

이 구문은 선택적으로 문자열 검색 기능을 제공할 것이다. 만약에 title값이 없다면 모든 active 상태의 Blog가 리턴될 것이다. 하지만 title 값이 있다면 그 값과 비슷한 데이터를 찾게 될 것이다.

title과 author를 사용하여 검색하고 싶다면?

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

02_ trim, where, set

앞서 예제는 악명높게 다양한 엘리먼트가 사용된 동적 sql이다. "if" 예제를 사용해보자

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

 어떤 조건에도 해당하지 않는다면 어떤 일이 벌어질까? 아마도 다음과 같은 sql이 만들어질 것이다.

SELECT * FROM BLOG
WHERE

아마도 이건 실패할 것이다. 두번째 조건에만 해당된다면 무슨 일이 벌어질까> 아마도 다음과 같은 sql이 만들어질 것이다.

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

이것도 아마 실패할 것이다. 실패하지 않기 위해서는 수정해야 한다.

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where엘리먼트는 태그에 의해 컨텐츠가 리턴되면 단순히 "where"만을 추가한다. 게다가 컨텐츠가 "and"나 "or"로 시작한다면 그 "and"나 "or"를 지워버린다.

 

만약에 where 엘리먼트가 기대한 것처럼 작동하지 않는다면 trim엘리먼트를 사용자 정의할 수도 있다. 예를들어 다음은 where엘리먼트에 대한 trim기능과 동일하다.

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

override 속성은 오버라이드하는 텍스트의 목록을 제한한다. 결과는 override속성에 명시된 것들을 지우고 with속성에 명시된 것을 추가한다.

다음 예제는 동적인 update구문의 유사한 경우이다. set엘리먼트는 update하고자 하는 칼럼을 동적으로 포함시키기 위해 사용될 수 있다. 

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

여기서 set 엘리먼트는 동적으로 set키워드를 붙히고 필요없는 콤마를 제거한다. 

trim 엘리먼트로 처리하면 아래와 같다.

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

03_ foreach

동적 sql 에서 공통적으로 필요한 것은 collection 에 대해 반복처리를 하는 것이다. 종종 in조건을 사용하게 된다. 예를 들면

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

foreach엘리먼트는 collection을 명시하는 것을 허용한다. 엘리먼트 내부에서 사용할 수 있는 item, index두가지 변수를 선언한다. 이 엘리먼트는 또한 열고 닫는 문자열로 명시할 수 있고 반복간에 둘 수 있는 구분자도 추가할 수 있다.

※컬렉션 파라미터로 map이나 배열객체와 더불어 list나 set등과 같은 반복가능한 객체를 전달 할 수 있다. 반복가능하거나 배열을 사용할때 index값은 현재 몇번째 반복인지를 나타내고 value항목은 반복과정에서 가져오는 요소를 나타낸다. 

 

04_ bind

bind엘리먼트는 OGNL표현을 사용해서 변수를 만든 뒤 컨텍스트에 바인딩한다. 

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

 

반응형

'백엔드 > myBatis' 카테고리의 다른 글

자바 API  (0) 2020.07.06
Mapper XML파일  (0) 2020.07.04
매퍼 설정  (0) 2020.07.01
myBatis 시작하기  (0) 2020.06.30
myBatis 개념  (0) 2020.06.22
Comments