스프링

스프링 DB 2 정리 - 4. 데이터 접근 기술 - MyBatis (22.8.26)

dodo4723 2024. 2. 13. 18:05
728x90
반응형

사용자가 특정 차트를 고르면, 전 종목의 과거(10년) 차트들을 모두 탐색하여 가장 유사한 차트 10개를 골라 사용자에게 보여줍니다.

 

웹프로젝트 링크

 

비슷한 차트 검색기

전 종목의 최근 10년간 모든 차트를 탐색합니다. 내 종목의 차트는 과연 상승하는 차트일까요?

www.similarchart.com

 

 

 

 

 

 

 

 

 

김영한 개발자님의 스프링 DB 2편 강의를 수강하고 중요한 내용을 정리했습니다.

 

4.1. MyBatis 소개

  • MyBatisJdbcTemplate보다 더 많은 기능을 제공하는 SQL Mapper이다.
  • 기본적으로 JdbcTemplate이 제공하는 대부분의 기능을 제공한다.
  • JdbcTemplate과 비교해서 MyBatis의 가장 매력적인 점은 SQL을 XML에 편리하게 작성할 수 있고 동적 쿼리를 매우 편리하게 작성할 수 있다는 점이다.

JdbcTemplate - SQL 여러 줄

String sql = "update item " +
 "set item_name=:itemName, price=:price, quantity=:quantity " +
 "where id=:id";

MyBatis - SQL 여러 줄

MyBatis는 XML에 작성하기 때문에 라인이 길어져도 문자 더하기에 대한 불편함이 없다.

<update id="update">
     update item
     set item_name=#{itemName},
     price=#{price},
     quantity=#{quantity}
     where id = #{id}
</update>

MyBatis - 동적 쿼리

JdbcTemplate은 자바 코드로 직접 동적 쿼리를 작성해야 하지만, MyBatis는 동적 쿼리를 매우 편리하게 작성할 수 있는 다양한 기능들을 제공해 준다.

<select id="findAll" resultType="Item">
     select id, item_name, price, quantity
     from item
     <where>
         <if test="itemName != null and itemName != ''">
             and item_name like concat('%',#{itemName},'%')
        </if>
        <if test="maxPrice != null">
             and price &lt;= #{maxPrice}
         </if>
     </where>
</select>

 

4.2. MyBatis 적용

MyBatis를 적용하기 위해서는 매핑 XML을 호출해 주는 매퍼 인터페이스가 필요하다.

@Mapper // 이걸 해줘야 MyBatis에서 인식할 수 있다.
public interface ItemMapper {
     void save(Item item);

     void update(@Param("id") Long id, @Param("updateParam") ItemUpdateDto updateParam);

     Optional<Item> findById(Long id);

     List<Item> findAll(ItemSearchCond itemSearch);
}

실행할 SQL이 있는 XML 매핑 파일을 src/main/resources 하위에 패키지 위치를 맞춰서 만들어야 한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hello.itemservice.repository.mybatis.ItemMapper">

<!-- Insert가 끝나면 item 객체의 id 속성에 데이터베이스가 생성한 키 값이 입력됨. -->
     <insert id="save" useGeneratedKeys="true" keyProperty="id">
         insert into item (item_name, price, quantity)
         values (#{itemName}, #{price}, #{quantity})
     </insert>

<!-- 파라미터가 2개 이상이면 인터페이스에 @Param 으로 이름을 지정-->
     <update id="update"> 
         update item
         set item_name=#{updateParam.itemName},
         price=#{updateParam.price},
         quantity=#{updateParam.quantity}
         where id = #{id}
     </update>

     <select id="findById" resultType="Item">
         select id, item_name, price, quantity
         from item
         where id = #{id}
     </select>

  <!-- SQL의 결과를 편리하게 객체로 바로 변환 -->
     <select id="findAll" resultType="Item">
         select id, item_name, price, quantity
         from item
         <where>
             <if test="itemName != null and itemName != ''">
                 and item_name like concat('%',#{itemName},'%')
             </if>
             <if test="maxPrice != null">
            <!-- < , > 같은 특수문자 사용불가-->
            <!-- CDATA나  < : &lt; > : &gt; & : &amp; 사용-->
            <![CDATA[
                 and price <= #{maxPrice}
            ]]>
                 and price &lt;= #{maxPrice}
             </if>
         </where>
     </select>
</mapper>
  • id 에는 매퍼 인터페이스에 설정한 메서드 이름을 지정하면 된다.
  • 파라미터는 #{} 문법을 사용하면 된다. 그리고 매퍼에서 넘긴 객체의 프로퍼티 이름을 적어주면 된다.

 

분석

ItemMapper 매퍼 인터페이스의 구현체가 없는데 어떻게 동작했을까?

애플리케이션 로딩 시점에 MyBatis 스프링 연동 모듈은 @Mapper 가 붙어있는 인터페이스를 조사하여 프락시 기술을 사용해서 ItemMapper 인터페이스의 구현체를 만든다.

매퍼 구현체는 예외 변환까지 처리해 준다. MyBatis에서 발생한 예외를 스프링 예외 추상화인 DataAccessException에 맞게 변환해서 반환해 준다.

 

4.3. MyBatis 기능 정리

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

1. if

SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
     AND title like #{title}
</if>
  • 해당 조건에 따라 값을 추가할지 말지 판단한다.

 

2. choose, when, otherwise

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>
  • switch 구문과 유사하다.

 

3. where

 SELECT * FROM BLOG
 <where>
     <if test="state != null">
         state = #{state}
     </if>
     <if test="title != null">
         AND title like #{title}
     </if>
</where>
  • <where>는 문장이 없으면 where를 추가하지 않고 있으면 추가한다.
  • 만약 and 가 먼저 시작된다면 and를 지운다.

 

4. foreach

SELECT *
    FROM POST P
     <where>
     <foreach item="item" index="index" collection="list"
         open="ID in (" separator="," close=")" nullable="true">
     #{item}
     </foreach>
</where>
  • 컬렉션을 반복 처리할 때 파라미터로 List를 전달하면 된다.
  • where in (1,2,3,4,5,6)와 같은 문장을 쉽게 완성할 수 있다.

 

5. 애노테이션으로 SQL 작성

@Select("select id, item_name, price, quantity from item where id=#{id}")
Optional<Item> findById(Long id);
  • @Insert , @Update , @Delete , @Select 기능이 제공된다.
  • 이 경우 XML에는 <select id="findById"> ~ </select>는 제거해야 한다.
  • 동적 SQL이 해결되지 않으므로 간단한 경우에만 사용한다.

 

6. 문자열 대체(String Substitution)

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
  • 는파라미터 바인딩이 아니라 문자 그대로를 처리하고 싶은 경우 ${}를 사용하면 된다.
반응형