Java & Spring

MyBatis

nippycloud 2025. 11. 15. 20:20

MyBatis는 DB에 전달할 SQL을 XML 파일에 작성하는 방식의 자바 진영 데이터 접근 기술 라이브러리이다.

MyBatis의 장점 : 동적 쿼리를 매우 편리하게 작성 가능

 

<목차>

1. 스프링에서 MyBatis 적용 방법

2. 스프링에서 MyBatis 사용 방법

3. XML 파일

4. Mapper 인터페이스 구현체

 

<스프링에서 MyBatis 적용 방법>

 

1. build.gradle 추가

implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' 

스프링 부트 버전이 2.x가 아닌 3.x라면 3.0.3을 넣어야 한다.

 

2. application.properties 편의 기능 추가

main, test 디렉토리 모두 적용해야 테스트 상황에서까지 같이 적용된다.

- mybatis.type-aliases-package=패키지 이름

- mybatis.configuration.map-underscore-to-camel-case=true 

- loggin.level.패키지 이름.mybatis=trace

 

Ex : 패키지 이름 

src.main 바로 하위에 있는 디렉토리부터 전부 써야 한다.

mybatis.type-aliases-package=hello.itemservice.domain

=> mybatis에서는 타입 정보를 사용 시 패키지 이름을 풀네임으로 작성해야 하는데,

풀네임이 길기 때문에 application.properties에서 alias를 설정해서 생략할 수 있게 한다.

 

mybatis.configuration.map-underscore-to-camel-case=true

=> 스프링에서 itemName의 데이터를 DB에 전달할 경우 DB에 item_Name으로 전달한다.

 

loggin.level.hello.itemservice.domain.mybatis=trace

@Mapper로 설정된 인터페이스가 들어간 위치를 디렉토리로 넣는다.

=> mybatis에서 실행되는 쿼리 로그를 확인할 수 있다.

 

 

<스프링에서 MyBatis 사용 방법>

 

1. Repository 계층 (디렉토리) 속에 mybatis 디렉토리를 생성한다. (다른 위치에 생성해도 된다.)

 

2. src/main/resources 디렉토리에도 Repository 계층 속 mybatis 디렉토리까지 똑같이 생성해서 만들어야 한다.

    ex) src/main/java/hello.itemservice.repository.mybatis 생성 시

    src/main/resources/hello.itemservice.repository.mybatis 도 만들어야 한다.

 

3. src/main/java/ ... / mybatis 디렉토리 속에 인터페이스를 하나 생성하고 (ex: ItemMapper) 클래스 레벨에 @Mapper을 붙인다.

@Mapper : XML 파일 속 SQL을 인식하고 DB에 전달하는 중요한 역할을 한다.

 

4. 기본적인 crud 메서드를 정의한다.

package hello.itemservice.repository.mybatis;
import hello.itemservice.domain.Item;
import hello.itemservice.repository.*;
import org.apache.ibatis.annotations.*;
import java.util.*;

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

 

 

5. resource 하위에 생성해준 / mybatis 패키지 속에 XML 파일을 생성한다. (ex: ItemMapper.xml)

반드시 @Mapper 어노테이션이 붙은 인터페이스와 같은 위치이어야 한다.

src.main.java.hello.itemservice.repository.mybatis.ItemMapper.java (인터페이스)

src.main.resource.hello.itemservice.repository.mybatis.ItemMapper.xml (XML 파일)

 

 

 

<XML 파일>

 

<?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 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>

 

 

1. application.properties에서"hello.itemservice.domain.Item"를 정의해두었기에 resultType="Item"으로 생략이 가능하다.

alias를 정의하지 않았을 경우 resultType="hello.itemservice.domain.Item" 로 풀네임 작성 필요

 

 

2. select id, item_name 부분에서 item_name으로 입력한 결과를 itemName으로 바인딩한다.

application.properties에서 "mapUnderscoreToCamelCase=true"를 해두었기 때문이다.

 

 

3. xml - insert : save 메서드

<insert id="save" useGeneratedKeys="true" keyProperty="id">
    insert into item (item_name, price, quantity)
    values (#{itemName}, #{price}, #{quantity})
</insert>

 

id = "save"는 @Mapper 인터페이스의 save 메서드를 사용한다는 의미이다.

useGeneratedKeys="true": GeneratedValue처럼 기본키를 자동 증가

keyProperty="id" : Item 클래스의 id 필드를 대상

values (#{속성명1}, #{속성명2}, .. ) 방식으로 값을 바인딩한다.

 

 

4. xml - update : update 메서드

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

 

@Mapper 인터페이스의 update 메서드는 파라미터가 2개이다.

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

 

where id = #{id} 로 @Param("id") Long id가 들어간다.

set 부분에서 updateParam의 필드들이 들어간다.

 

 

5. xml - select : findAll 메서드 

MyBatis의 최대 강점은 유연한 동적 쿼리 작성이다.

findAll 메서드는 검색 조건 파라미터를 받아 동적 검색 쿼리를 전달해야 한다. (검색 조건에 따라 쿼리가 달라진다)

 

<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>

 

<where> ... </where> 을 이용해 동적 쿼리를 생성한다.

<if> .. </if> 조건문이 참이라면 and item_name like concat('%', #{itemName}, '%') 를 from절 다음에 추가한다.

만약 where문에서 첫 조건이라면 and 부분을 생략한다.

=> if절이 참일 경우 : ... from item where item_name like ... 으로 SQL이 작성된다.

 

and price &lt;= #{maxPrice}에서 &lt;=<=와 같으며, xml 파일에서 <, >는 태그로 취급되기 때문에

<는 &lt를 사용, >는 &gt; 사용

 

 

 

 

<Mapper 인터페이스 구현체>

package hello.itemservice.repository.mybatis;
import hello.itemservice.domain.Item;
import hello.itemservice.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.*;

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

 

MyBatisItemRepository는 ItemMapper의 기능을 그대로 사용한다.

ItemMapper 인터페이스의 구현체는 MyBatis 스프링 연동 모듈에서 자동으로 생성한다.

 

1) @Mapper가 있는 인터페이스 조회

2) MyBatis 스프링 연동 모듈은 @Mapper 인터페이스를 구현하는 동적 프록시 객체를 자동 생성

3) 동적 프록시 객체를 스프링 컨테이너에 빈으로 등록하여 사용 (빈으로 등록하는 역할은 Config 클래스가 수행한다.)

 

Config 클래스 생성 (ex : hello.itemservice.config 패키지 하위)

@Configuration
@MapperScan("hello.itemservice.repository.mybatis")
@RequiredArgsConstructor
public class MyBatisConfig {
    private final ItemMapper itemMapper;

    @Bean
    public ItemService itemService(){
        return new ItemService(itemRepository());
    }

    @Bean
    public ItemRepository itemRepository(){
        return new MyBatisItemRepository(itemMapper);
    }
}

 

1) itemRepository() 메서드가 itemMapper 객체를 담은 MyBatisItemRepository를 생성한다.

2) 생성한 리포지토리를 서비스 계층에 전달한다.

3) @Bean으로 직접 리포지토리와 서비스 계층을 스프링 빈으로 등록한다. (수동 빈 등록)

@MapperScan("hello.itemservice.repository.mybatis")

 

4) @MapperScan을 통해 해당 위치 속에서 @Mapper 인터페이스를 찾아 자동으로 구현체 생성, 빈으로 등록한다. (자동 빈 등록)

 

 

MyBatis 스프링 연동 모듈은 @Mapper 인터페이스의 구현체를 런타임에 자동으로 구현해주며, 예외 변환까지 처리한다.

XML 파일에서 SQL을 잘못 작성해도 MyBatis 예외가 아닌 스프링 예외가 발생한다.

'Java & Spring' 카테고리의 다른 글

[Servlet] WebSocket  (0) 2026.02.16
[Spring] Security  (0) 2026.02.15
[Java] Reflection  (0) 2026.01.01
[JAVA] JVM의 구조  (0) 2025.12.09
[Servlet] File Upload  (0) 2025.11.16