본문 바로가기
Spring/개념지식 및 에러사항

[MyBatis] 동적 SQL

by 태옹 2021. 8. 8.

동적 SQL

MyBatis의 가장 강력한 기능 중 하나는 동적 SQL을 처리하는 방법이다.

 

MyBatis의 동적 태그는 SQL을 파라미터들의 조건에 맞게 조정이 가능하게 하고,

약간의 구문을 이용해서 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어 주는 기능이 있다.

 

👇 MyBatis 동적 태그는 아래의 문서에서 기능들에 대한 설명 및 사용법을 확인할 수 있다.

https://mybatis.org/mybatis-3/ko/dynamic-sql.html

 

MyBatis – 마이바티스 3 | 동적 SQL

동적 SQL 마이바티스의 가장 강력한 기능 중 하나는 동적 SQL을 처리하는 방법이다. JDBC나 다른 유사한 프레임워크를 사용해본 경험이 있다면 동적으로 SQL 을 구성하는 것이 얼마나 힘든 작업인지

mybatis.org

 

동적 태그들은 <select>,<insert>,<update>,<delete> 태그의 내부에서 조건식처럼 사용할 수 있다.

아래에서는 동적 SQL의 다섯가지 표현식에 대해서 소개해보겠다.

 

단독으로 사용이 가능한 태그

◾ if

◾ choose

◾ foreach

 

단독으로 사용이 불가능한 태그 

◾ where

◾ trim

<if>,<choose>와 같은 태그들을 내포하여 sql을 연결해주고,

앞 뒤에 필요한 구문(AND, OR, WHERE, '( )' 등)을 추가하거나 생략하는 역할을 한다.

 

 


if

test라는 속성과 함께 특정한 조건이 true가 된 경우에 포함하고 싶은 sql을 사용하고자 할 때 사용한다.

예를 들어, 검색 조건이 'T'면 제목이 keyword인 항목을 검색하는 <if>태그는 다음과 같이 작성한다.

<if test="type=='T'.toString()">
	(title like '%'||#{keyword}||'%')
</if>

 

choose

<choose>는 내부에서 상황에 따른 처리를 위해 <when>을 사용하며, <choose>의 else인 <otherwise>를 함께 사용할 수 있다. choose-when은 switch-case문과 유사한 기능이라고 생각하면 쉽다.

if와 달리 여러 조건들 중 하나만 선택하여 동작한다.

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

 

where

SQL의 where조건식과 동일한 기능이다.

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

위의 코드처럼 작성하였다고 했을 때, 만약 bno값이 존재하는 경우에는 

SELECT * FROM tbl_board WHERE bno = 33

위의 쿼리처럼 where조건이 적용되어 처리될 것이고, bno값이 null인 경우에는 

SELECT * FROM tbl_board

위의 쿼리처럼 where조건은 무시된 채 처리가 될 것이다. 해당식을 사용하게 되면 list( )기능을 하는 mapper와 get( )기능을 하는 mapper를 따로 작성하지 않고도 각각의 쿼리를 처리할 수 있게 된다.

만약 where조건 안에 <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>
  </where>
</select>

위의 쿼리식에서 만약 state가 null이라서 맨 처음의 <if>가 무시되고, title은 null값이 아니라서 두번째 <if>부터 처리된다고 가정할 때, WHERE AND title like #{title}로 처리되는 것이 아니라 WHERE title like #{title}로 처리를 해준다. AND나 OR로 시작하는 경우에는 자동으로 AND,OR을 지워준다.

이러한 기능이 유용할 수 있겠지만 기대했던 동작을 하지 않을 수 있다는 단점이 있다. 그런 경우 <trim>을 사용해서 사용자가 직접 제어할 수 있다.

 

trim

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

prefix, suffix, prefixOverrides, suffixOverrides 옵션을 지정하여 상황에 맞게 작성이 가능하다.

SELECT * FROM tbl_board
    <where>
        <if test="bno!=null">
        	bno = #{bno}
        </if>
        <trim prefix="and">
        	rownum=1
        </trim>
    </where>

위의 코드처럼 작성하였다고 했을 때, 만약 bno값이 존재하는 경우에는 

SELECT * FROM tbl_board WHERE bno = 33 AND rownum = 1

위의 쿼리처럼 where조건이 적용되어 처리될 것이고, bno값이 null인 경우에는 

SELECT * FROM tbl_board AND rownum = 1

where조건은 빠지되, trim태그의 쿼리는 붙게 된다. 이런 경우에는 문법적 오류가 있는 쿼리이니 주의하면서 작성하도록 한다.

 

👇 아래의 포스팅에서 trim에 대한 자세한 내용을 소개하였으니 참고하기!

https://java119.tistory.com/103

 

[MyBatis] 동적 쿼리 개념 및 문법 총 정리

속성 prefix : 실행될 쿼리의 문 안에 쿼리 가장 앞에 붙여준다. UPDATE board username=#{username},password=#{password} prefixOverrides : 실행될 쿼리의 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자..

java119.tistory.com

 

foreach

foreach는 List, 배열, Map 등의 데이터를 순회하여 처리할 수 있다.

만약 HashMap<>타입의 객체에 원하는 정보를 넣어놓고,

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

해당 객체를 순회하도록 쿼리를 작성하는 경우 <foreach> 내부에 반복할 구문을 작성할 수 있다. 

SELECT * FROM tbl_board
  <trim prefix="where (" suffix=")" prefixOverrides="OR">
    <foreach item="val" index="key" collection="map">
      <trim prefix="OR">
        <if test="type=='T'.toString()">
        	title = #{val}
        </if>
        <if test="type=='C'.toString()">
        	content = #{val}
        </if>
      </trim>
    </foreach>
  </trim>

 

배열이나 List를 이용하는 경우에는 item속성만을 이용하면 되고,

Map의 형태로 key와 value를 이용해야 할 때는 index와 item속성을 둘 다 이용한다. 

실제 SQL은 아래와 같이 처리된다.

 

SELECT * FROM tbl_board
where (content = 'CCCC' OR title='TTTT')

'Spring > 개념지식 및 에러사항' 카테고리의 다른 글

Servlet vs Spring MVC  (0) 2021.12.27
[Spring] JPA CRUD  (0) 2021.07.13
[Spring] JPA 기초  (0) 2021.07.12
RestController 생성하기  (0) 2021.07.05
Log4j import에러  (0) 2021.07.02

댓글