특징

  • 자원 생성 해제 필요 X
  • 파라미터, 결과셋 설정 코드 X
  • SQL문을 따로 관리(xml or 인터페이스)
  • 구성요소 5가지 : 설정파일, 매퍼, 파라미터타입(parameterType), 결과타입(resultType),결과매핑(resultMap)
  • 파라미터, 결과 타입 : Map객체, Java 모델 클래스, 원시타입

  • 속성명과 변수명이 다를때 맵핑하는 방법은 resultMap을 사용하거나 Alias를 사용함 (Alias 권장)
  • #{} 와 ${}의 차이점
    • # : 문자면 ‘   ’를 달아줌 (숫자의경우 ‘  ‘을 달지않음)
    • $ : 어떠한 경우도 ‘  ‘을 달지않음
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'

매퍼 설정

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/test
    username: sa
mybatis:
  type-aliases-package: hello.itemservice.domain
  configuration.map-underscore-to-camel-case: true

ItemMapper

  • MyBatis 매퍼 XML을 호출해주는 인터페이스
  • 이 인터페이스의 메서드를 호출하면 같은 이름을 갖는 id의 SQL이 실행된다
@Mapper
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);
}

ItemMapper.xml (매퍼 XML)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
	
<mapper namespace="hello.itemservice.repository.mybatis.ItemMapper">    <!-- Mapper Interface -->
    <cache />
    <insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into item (item_name, price, quantity)
        values (#{itemName}, #{price}, #{quantity})
    </insert>
    <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">    <!-- type-aliases-package 위치 -->
        select id, item_name, price, quantity
        from item
        where id = #{id}
    </select>
    <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>
</mapper>

→ #{}를 사용할 때 parameterType이 hashmap일경우 key값, DTO일경우 getter를 의미함

Repository

@Repository
@RequiredArgsConstructor
public class MyBatisItemRepository implements ItemRepository {
    private final ItemMapper itemMapper;

    @Override
    public Item save(Item item) {
        itemMapper.save(item);
        return item;
    }
    @Override
    public void update(Long itemId, ItemUpdateDto updateParam) {
        itemMapper.update(itemId, updateParam);
    }
    @Override
    public Optional<Item> findById(Long id) {
        return itemMapper.findById(id);
    }
    @Override
    public List<Item> findAll(ItemSearchCond cond) {
        return itemMapper.findAll(cond);
    }
}

요소

  • sql : 재사용 가능한 sql구문 정의 (id부여)
    • 요소를 사용하여 SQL에 삽입
<sql id="BaseColumns">
    comment_no AS commentNo,
    user_id AS userId,
    comment_content AS commentContent,
    reg_date AS regDate
</sql>
  • select
<select id="selectComment" parameterType="hashmap" resultType="mybatis.Comment">
    SELECT
        <include refid="BaseColumns" />
    FROM comment
</select>
  • insert, update, delete
    • result가 없으므로 파라미터타입만 기입 (resultType, resultMap 필요 X)
<update id="insertComment" parameterType="Comment">
    UPDATE tcomment SET comment_content = #{commentContent} WHERE comment_no = #{commentNo}
</update>
  • where : where절 사용
    • SQL구문에 WHERE를 추가, 게다가 구문이 AND 나 OR로 시작하면 그 구문을 지워줌 
  • if
<where>
    <if test="commentNo != null">
        comment_no = #{commentNo}
    </if>
    <if test="userId != null">
        AND user_id = #{userId}
    </if>
</where>
  • choose, when, otherwise : switch-case-default 구문
<select id="selectCommentByConditionChoose" parameterType="hashmap" resultType="Comment">
    SELECT comment_no AS commentNo, user_id AS userId, comment_content AS commentContent, reg_date AS regDate FROM tcomment
    <choose>
        <when test="commentNo != null">
            WHERE comment_no = #{commentNo}
        </when>
        <when test="userId != null">		<!-- 첫번째 when에 걸릴경우 실행되지 않음 -->
            WHERE user_id = #{userId}
        </when>
        <otherwise>				<!-- 첫번째 when에 걸릴경우 실행되지 않음 -->
            WHERE comment_no = 1 AND user_id = 'from'
        </otherwise>
    </choose>
</select>
  • foreach : IN 구문에 많이 사용함
  • collection : 배열 or 컬렉션
  • item : each값
  • index : 인덱스
  • separator : 각 값의 구분자
  • open, close : 시작과 끝에 삽입할 문자
<select id="selectCommentByConditionForeach" parameterType="hashmap" resultType="Comment">
    SELECT comment_no AS commentNo, user_id AS userId, comment_content AS commentContent, reg_date AS regDate FROM tcomment
    <where>
        <if test="commentNos != null">
            comment_no IN
            <foreach collection="commentNos" item="commentNo" index="index" open="(" close=")" separator=", ">	<!-- (?, ?) -->
                #{commentNo}		<!-- item값 -->
            </foreach>
        </if>
    </where>
</select>
  • selectKey : selectKey 구문이 먼저 실행되고 keyProperty에 결과를 넣은 후 그아래 SQL문이 실행됨
    • keyProperty : selectKey 구문의 결과가 셋팅될 프로퍼티
    • order : selectKey 구문의 순서 설정, SQL이 수행되기 전(BEFORE)인지 후(AFTER)인지
<insert id="insertCommentKey" parameterType="Comment">
	<selectKey keyProperty="commentNo" resultType="long" order="BEFORE">
		SELECT max(comment_no)+1 FROM tcomment
	</selectKey>
	INSERT INTO tcomment(comment_no, user_id, comment_content, reg_date)
		VALUES (#{commentNo}, #{userId}, #{commentContent}, #{regDate})
</insert>