[Spring DB] MyBatis

2025. 7. 7. 06:57코딩 도구/백엔드 개발 (Backend Development)

반응형

MyBatis 정리

이 글은 인프런 김영한님의 "스프링 DB 2편 - 데이터 접근 활용 기술" 강의를 수강하고 정리한 내용이다.

 

이번 글에서는 MyBatis의 기본 개념부터 설정, 동적 쿼리 작성, 기타 고급 기능까지 실무에서 활용할 수 있는 전체 흐름을 가볍게 정리한다. MyBatis는 SQL Mapper로서 XML 기반 쿼리 작성과 강력한 동적 쿼리 기능을 통해 복잡한 데이터 접근 요구사항을 효과적으로 해결할 수 있는 도구이다.


1. MyBatis 소개

MyBatis는 JDBC 또는 JdbcTemplate보다 더 강력한 기능을 제공하는 SQL Mapper 프레임워크이다.

  • SQL을 XML로 분리하여 유지보수가 용이하다.
  • 동적 쿼리 작성이 편리하다.
  • 자바 객체와 SQL 쿼리 간의 매핑을 자동화한다.

예시: SQL 여러 줄 비교

JdbcTemplate

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

MyBatis (XML)

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

2. 설정 및 의존성 추가

implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
  • 스프링 부트 3.0 이상에서는 3.0.3 사용

application.properties

mybatis.type-aliases-package=hello.itemservice.domain
mybatis.configuration.map-underscore-to-camel-case=true
logging.level.hello.itemservice.repository.mybatis=trace
  • 카멜 케이스 자동 매핑을 위해 map-underscore-to-camel-case=true를 설정한다.

3. 기본 사용 예시

Mapper 인터페이스

@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 cond);
}

매핑 XML 파일

<mapper namespace="hello.itemservice.repository.mybatis.ItemMapper">
  <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">
    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>

XML 특수문자 <, >&lt;, &gt;로 치환해야 한다. CDATA도 사용 가능하다.


4. 동적 쿼리 기능 정리

MyBatis는 다양한 XML 태그로 동적 쿼리를 지원한다:

  • <if>: 조건문
  • <choose>, <when>, <otherwise>: switch-case 구조
  • <where>: WHERE 절 자동 처리
  • <trim>: WHERE 또는 SET 자동 트리밍
  • <foreach>: 반복 처리 (IN 절 등)

foreach 예시

<foreach item="item" collection="list" open="(" separator="," close=")">
  #{item}
</foreach>

5. 기타 기능들

애노테이션 기반 쿼리

@Select("select * from item where id=#{id}")
Optional<Item> findById(Long id);

간단한 쿼리에는 유용하지만 동적 쿼리에는 부적합하다.

문자열 치환 (${})

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

SQL 인젝션 위험이 있으므로 주의가 필요하다.

SQL 조각 재사용 (<sql>)

<sql id="userColumns"> id, username, password </sql>
<include refid="userColumns"/>

결과 매핑 (ResultMap)

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id"/>
  <result property="username" column="user_name"/>
</resultMap>

 

별칭 없이도 커스텀 매핑이 가능하며, 복잡한 객체 관계도 매핑할 수 있다.


6. 실행 및 통합 구성

Repository 구현체

@Repository
@RequiredArgsConstructor
public class MyBatisItemRepository implements ItemRepository {
    private final ItemMapper itemMapper;
    public Item save(Item item) { return itemMapper.save(item); }
    public void update(Long id, ItemUpdateDto dto) { itemMapper.update(id, dto); }
    public Optional<Item> findById(Long id) { return itemMapper.findById(id); }
    public List<Item> findAll(ItemSearchCond cond) { return itemMapper.findAll(cond); }
}

설정 클래스

@Configuration
@RequiredArgsConstructor
public class MyBatisConfig {
    private final ItemMapper itemMapper;
    @Bean
    public ItemService itemService() { return new ItemServiceV1(itemRepository()); }
    @Bean
    public ItemRepository itemRepository() { return new MyBatisItemRepository(itemMapper); }
}

7. MyBatis 내부 동작 원리

  • @Mapper가 붙은 인터페이스를 스캔
  • JDK 동적 프록시로 구현체 자동 생성 (com.sun.proxy.$Proxy)
  • XML 파일과 매핑되어 SQL 실행
  • 예외는 DataAccessException으로 변환됨 (스프링 예외 추상화 적용)

8. 정리

설정 mybatis-spring-boot-starter 사용하여 자동 설정 지원
쿼리 작성 XML 기반 또는 애노테이션 기반 선택 가능
동적 쿼리 <if>, <where>, <foreach> 등 강력한 기능 제공
예외 처리 스프링의 예외 추상화 (DataAccessException) 연동
실행 원리 인터페이스 + XML 기반 자동 프록시 생성

 

MyBatis는 SQL 중심 개발에 최적화된 프레임워크이며, 복잡한 조건과 쿼리를 명시적으로 제어해야 할 때 강력한 선택지가 된다.

반응형