mybatis 공부 : 기능 정리 - 동적 쿼리

Chooooo·2023년 11월 3일
0

인턴생활

목록 보기
9/19

기능정리1 - 동적 쿼리

MyBatis에서 자주 사용하는 주요 기능을 공식 메뉴얼에 제공하는 예제를 통해 간단히 정리하겠다.

[MyBatis 공식 메뉴얼]
[MyBatis 스프링 공식 메뉴얼]

동적 SQL

MyBatis가 제공하는 최고의 기능이자 MyBatis를 사용하는 이유는 바로 동적 SQL 기능 때문이다.

동적 쿼리를 위해 제공되는 기능은 아래와 같다.

  • if
  • choose (when otherwise)
  • trim (where, set)
  • foreach

공식 메뉴얼에서 제공하는 예제를 통해 동적 SQL을 알아보자.

if

<select id="findActiveBlogWithTitleLike"
 resultType="Blog">
 SELECT * FROM BLOG
 WHERE state = ‘ACTIVE’
 <if test="title != null">
 AND title like #{title}
 </if>
</select>
  • 해당 조건에 따라 값을 추가할지 말지 판단한다.
  • 내부의 문법은 OGNL을 사용한다. (몰라도 됨)

choose, when, otherwise

<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>
  • 자바의 switch 구문과 유사한 구문도 사용할 수 있다.

trim, where, set

<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> 를 사용하면 이런 문제를 해결할 수 있다.

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>

foreach

<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>
  • 컬렉션을 반복 처리할 때 사용한다. where in (1,2,3,4,5,6) 와 같은 문장을 쉽게 완성할 수 있다.
  • 파라미터로 List 를 전달하면 된다.

참고
동적 쿼리에 대한 자세한 내용은 다음을 참고하자.
https://mybatis.org/mybatis-3/ko/dynamic-sql.html

MyBatis 기능 정리2 - 기타 기능

어노테이션으로 SQL 작성

  • 다음과 같이 XML 대신에 어노테이션에 SQL을 작성할 수 있다.
@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

문자열 대체(String substitution)

#{} 문법은 ?를 넣고 파라미터를 바인딩하는 PreparedStatement 를 사용한다.
때로는 파라미터 바인딩이 아니라 문자 그대로를 처리하고 싶은 경우도 있다. 이때는 ${} 를 사용하면 된다.
다음 예제를 보자
ORDER BY ${columnName}

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String 
value);

재사용 가능한 SQL 조각

<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>
  • 프로퍼티 값을 전달할 수 있고, 해당 값은 내부에서 사용할 수 있다.

Result Maps

결과를 매핑할 때 테이블은 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 을 선언해서 사용하면 된다.
<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

profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글