MyBatis에서 자주 사용하는 주요 기능을 공식 메뉴얼에 제공하는 예제를 통해 간단히 정리하겠다.
[MyBatis 공식 메뉴얼]
[MyBatis 스프링 공식 메뉴얼]
MyBatis가 제공하는 최고의 기능이자 MyBatis를 사용하는 이유는 바로 동적 SQL 기능 때문이다.
동적 쿼리를 위해 제공되는 기능은 아래와 같다.
if
choose (when otherwise)
trim (where, set)
foreach
공식 메뉴얼에서 제공하는 예제를 통해 동적 SQL을 알아보자.
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
<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>
-0 이 예제의 문제점은 문장을 모두 만족하지 않을 때 발생한다.
SELECT * FROM BLOG
WHERE
-1 title 만 만족할 때도 문제가 발생한다.
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
결국 WHERE 문을 언제 넣어야 할지 상황에 따라서 동적으로 달라지는 문제가 있다.
<where>
를 사용하면 이런 문제를 해결할 수 있다.
<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 를 추가하지 않는다. 문장이 있으면 where 를 추가한다. 만약 and 가
먼저 시작된다면 and 를 지운다.
😓 참고로 다음과 같이 trim 이라는 기능으로 사용해도 된다. 이렇게 정의하면 <where>
와 같은 기능을
수행한다.
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>
참고
동적 쿼리에 대한 자세한 내용은 다음을 참고하자.
https://mybatis.org/mybatis-3/ko/dynamic-sql.html
@Select("select id, item_name, price, quantity from item where id=#{id}")
Optional<Item> findById(Long id);
@Insert , @Update , @Delete , @Select 기능이 제공된다.
이 경우 XML에는 ~ 는 제거해야 한다.
동적 SQL이 해결되지 않으므로 간단한 경우에만 사용한다.
애노테이션으로 SQL 작성에 대한 더 자세한 내용은 다음을 참고하자.
https://mybatis.org/mybatis-3/ko/java-api.html
#{}
문법은 ?를 넣고 파라미터를 바인딩하는 PreparedStatement 를 사용한다.
때로는 파라미터 바인딩이 아니라 문자 그대로를 처리하고 싶은 경우도 있다. 이때는 ${}
를 사용하면 된다.
다음 예제를 보자
ORDER BY ${columnName}
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String
value);
<sql>
을 사용하면 SQL 코드를 재사용할 수 있다.
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
<include>
를 통해서 <sql>
조각을 찾아서 사용할 수 있다.<sql id="sometable">
${prefix}Table
</sql>
<sql id="someinclude">
from
<include refid="${include_target}"/>
</sql>
<select id="select" resultType="map">
select
field1, field2, field3
<include refid="someinclude">
<property name="prefix" value="Some"/>
<property name="include_target" value="sometable"/>
</include>
</select>
결과를 매핑할 때 테이블은 user_id 이지만 객체는 id 이다.
이 경우 컬럼명과 객체의 프로퍼티 명이 다르다. 그러면 다음과 같이 별칭( as )을 사용하면 된다.
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
😓 참고 blog