동적 SQL
MyBatis의 가장 강력한 기능 중 하나는 동적 SQL을 처리하는 방법이다.
MyBatis의 동적 태그는 SQL을 파라미터들의 조건에 맞게 조정이 가능하게 하고,
약간의 구문을 이용해서 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어 주는 기능이 있다.
👇 MyBatis 동적 태그는 아래의 문서에서 기능들에 대한 설명 및 사용법을 확인할 수 있다.
https://mybatis.org/mybatis-3/ko/dynamic-sql.html
동적 태그들은 <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
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 |
댓글