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 <= #{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 <= #{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 <= #{maxPrice}에서 <= 는 <=와 같으며, xml 파일에서 <, >는 태그로 취급되기 때문에
<는 <를 사용, >는 > 사용
<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 |