MyBatis를 Spring Boot에서 쓰려면 SqlSessionFactory를 직접 만들어야 할까요?

mybatis-spring-boot-starter를 사용하면 SqlSessionFactory, SqlSessionTemplate, DataSource 설정이 모두 자동으로 구성됩니다. application.yml에 DB 정보만 적으면 바로 쿼리를 실행할 수 있습니다.

개념 정의

mybatis-spring-boot-starter 는 Spring Boot의 Auto Configuration으로 MyBatis를 자동 설정하는 스타터 의존성입니다. DataSource 빈을 감지하면 SqlSessionFactory와 SqlSessionTemplate을 자동으로 생성합니다.

왜 필요한가

  • **수동 설정 제거 **: 순수 MyBatis에서는 mybatis-config.xml에 DataSource, TypeHandler, Mapper 경로를 모두 직접 설정합니다. 스타터는 이 과정을 자동화합니다.
  • **Spring 트랜잭션 통합 **: @Transactional이 MyBatis의 SqlSession과 자연스럽게 연동됩니다.
  • **Spring Boot 생태계 활용 **: Actuator, Testcontainers 등 Spring Boot 도구와 바로 호환됩니다.

설정 단계

의존성 추가

XML
<!-- pom.xml -->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>3.0.3</version>
</dependency>

이 하나의 의존성이 mybatis, mybatis-spring, spring-boot-starter-jdbc를 모두 포함합니다.

application.yml 설정

YAML
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.domain
  configuration:
    map-underscore-to-camel-case: true

각 설정의 역할을 정리합니다.

설정역할
mapper-locationsXML Mapper 파일의 경로 패턴
type-aliases-packageresultType="User"처럼 풀 패키지 없이 클래스명만 사용 가능
map-underscore-to-camel-caseuser_nameuserName 자동 매핑

map-underscore-to-camel-case: true는 거의 필수입니다. 이 설정 없이는 DB의 snake_case 컬럼이 자바의 camelCase 필드에 매핑되지 않습니다.

@Mapper vs @MapperScan

Mapper 인터페이스를 Spring 빈으로 등록하는 두 가지 방법이 있습니다.

@Mapper — 인터페이스마다 개별 등록

JAVA
@Mapper  // ← 이 인터페이스를 Mapper 빈으로 등록
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
}

@MapperScan — 패키지 단위로 일괄 등록

JAVA
@SpringBootApplication
@MapperScan("com.example.mapper")  // ← 이 패키지의 모든 인터페이스를 Mapper로 등록
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
방식장점단점
@Mapper어떤 인터페이스가 Mapper인지 명확인터페이스마다 붙여야 함
@MapperScan한 번에 등록, 새 Mapper 추가 시 설정 불필요의도치 않은 인터페이스도 등록될 수 있음

소규모 프로젝트에서는 @Mapper로 충분하고, Mapper가 많아지면 @MapperScan이 편리합니다.

트랜잭션 연동

mybatis-spring은 Spring의 PlatformTransactionManager와 통합됩니다. @Transactional을 그대로 사용할 수 있습니다.

JAVA
@Service
@RequiredArgsConstructor
public class OrderService {
    private final OrderMapper orderMapper;
    private final PaymentMapper paymentMapper;

    @Transactional  // ← Spring 트랜잭션
    public void createOrder(OrderRequest request) {
        orderMapper.insert(request.toOrder());
        paymentMapper.insert(request.toPayment());
        // 예외 발생 시 두 INSERT 모두 롤백
    }
}

이것이 가능한 이유는 SqlSessionTemplate이 Spring의 트랜잭션 동기화 매니저에 연결되기 때문입니다.

  1. @Transactional이 트랜잭션을 시작합니다.
  2. SqlSessionTemplate은 현재 트랜잭션에 바인딩된 커넥션을 사용합니다.
  3. 같은 트랜잭션 안의 모든 Mapper 호출이 같은 커넥션을 공유합니다.
  4. 메서드 종료 시 커밋 또는 롤백됩니다.

Auto Configuration이 하는 일

스타터가 자동으로 생성하는 빈을 정리합니다.

PLAINTEXT
DataSource (spring.datasource 설정 기반)


SqlSessionFactory (DataSource + mybatis 설정 조합)


SqlSessionTemplate (스레드 안전한 SqlSession 래퍼)


Mapper 프록시 빈 (@Mapper 또는 @MapperScan으로 등록)

Spring Boot 없이 동일한 구성을 수동으로 하려면 @Bean 메서드 3~4개를 직접 작성해야 합니다. 스타터가 이 보일러플레이트를 제거합니다.

주의할 점

mapper-locations 경로 실수

YAML
# 잘못된 경로: src/main/resources 기준이 아니라 classpath 기준
mybatis:
  mapper-locations: mapper/*.xml           # ← classpath: 접두어 누락

# 올바른 경로
mybatis:
  mapper-locations: classpath:mapper/*.xml

classpath: 접두어를 빠뜨리면 Mapper XML을 찾지 못해 BindingException이 발생합니다. "분명히 XML 파일이 있는데 왜 못 찾지?" 상황의 대부분이 이 원인입니다.

@Mapper와 @MapperScan 중복 사용

둘을 동시에 쓰면 같은 Mapper가 두 번 등록될 수 있습니다. 빈 충돌은 발생하지 않지만 혼란의 원인이 됩니다. 팀에서 하나의 방식으로 통일하는 것이 좋습니다.

MyBatis와 JPA를 함께 쓸 때 트랜잭션 매니저 충돌

같은 프로젝트에서 JPA와 MyBatis를 함께 사용하면 PlatformTransactionManager 빈이 두 개 생길 수 있습니다. JpaTransactionManager는 JDBC도 지원하므로 보통 JPA 트랜잭션 매니저 하나로 통합할 수 있지만, DataSource가 다르면 별도 설정이 필요합니다.

정리

항목설명
스타터 역할SqlSessionFactory, SqlSessionTemplate 자동 생성
핵심 설정mapper-locations, type-aliases-package, map-underscore-to-camel-case
@Mapper인터페이스 개별 등록
@MapperScan패키지 단위 일괄 등록
트랜잭션Spring @Transactional 그대로 사용, SqlSessionTemplate이 자동 연동
주의 사항classpath: 접두어 필수, @Mapper와 @MapperScan 중복 피하기
댓글 로딩 중...