Categories
웹개발/Mybatis
MyBatis mybatis-config.xml Mapper XML 차이, 무엇을 어디에 써야 할까
Mapper 인터페이스는 있는데 SQL을 못 찾거나 resultType 필드가 null이면, 먼저 mybatis-config.xml과 Mapper XML의 책임부터 나눠야 한다. 파일 역할을 구분해야 설정 위치와 오류 원인을 빠르게 좁힐 수 있다.
핵심은 두 XML의 책임을 먼저 나누는 것이다. mybatis-config.xml은 전체 동작 기준을 정하는 파일이고, UserMapper.xml 같은 Mapper XML은 실제 SQL과 결과 매핑을 담는 파일이다. 전역 설정은 mybatis-config.xml에 두고, SQL 문장과 resultMap은 Mapper XML에 둔다고 잡으면 대부분의 설정 흐름이 정리된다. Spring MyBatis에서는 여기에 SqlSessionFactoryBean의 configLocation과 mapperLocations가 연결된다.
핵심 결론: mybatis-config.xml은 MyBatis 전체 동작 기준을 정하는 전역 설정이고, Mapper XML은 개별 SQL과 resultMap을 담는 실행 파일이다.
확인 순서: DataSource → SqlSessionFactoryBean → configLocation → mybatis-config.xml → mapperLocations → Mapper XML → namespace/id.
두 파일의 역할을 먼저 나눈다
mybatis-config.xml은 MyBatis 전체에 적용되는 설정을 담는다. 예를 들어 underscore 컬럼을 camelCase 필드로 자동 매핑할지, typeAlias를 어떻게 등록할지, 공통 TypeHandler를 쓸지 같은 설정이다. SQL 문장을 직접 많이 넣는 파일이 아니다.
반대로 Mapper XML은 실제 SQL을 담는다. select, insert, update, delete, resultMap, 동적 SQL 조건이 여기에 들어간다. 업무 기능별로 Mapper 인터페이스와 연결되어 실행된다.
둘의 차이를 한 문장으로 줄이면 이렇다. mybatis-config.xml은 MyBatis의 공통 동작을 정하고, Mapper XML은 특정 업무 SQL을 실행한다. 이 기준만 잡아도 설정 위치를 잘못 넣는 실수를 줄일 수 있다. MyBatis 설정 흐름을 큰 그림으로 먼저 보고 싶다면 설정 구조 비교처럼 역할을 나눠 보는 글과 같이 확인하면 이해가 빠르다.
mybatis-config.xml에는 무엇을 쓰나
settings로 전역 동작을 정한다
settings는 MyBatis 전체 동작을 조정한다. 대표적으로 많이 보는 설정은 mapUnderscoreToCamelCase다.
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
이 설정이 true이면 DB 컬럼 user_name을 Java 필드 userName에 매핑하는 식의 자동 변환을 기대할 수 있다. 다만 모든 상황을 해결해 주는 것은 아니다. 컬럼 alias가 이상하거나 resultMap이 별도로 정의되어 있으면 해당 설정만으로 해결되지 않을 수 있다.
조회 결과 필드가 null로 들어오는 문제는 settings와 resultMap을 같이 봐야 한다. 이 부분은 매핑 기준에서 resultType과 resultMap 기준으로 더 자세히 확인할 수 있다.
typeAliases로 클래스 이름을 줄인다
typeAliases는 Mapper XML에서 Java 클래스 전체 패키지명을 매번 쓰지 않도록 별칭을 등록하는 설정이다.
<configuration>
<typeAliases>
<typeAlias alias="User" type="com.example.domain.User"/>
</typeAliases>
</configuration>
패키지 전체를 등록할 수도 있다.
<configuration>
<typeAliases>
<package name="com.example.domain"/>
</typeAliases>
</configuration>
이렇게 해 두면 Mapper XML에서 resultType="User"처럼 짧게 쓸 수 있다. 다만 alias가 많아지면 어떤 클래스와 연결되는지 헷갈릴 수 있으므로, 패키지 구조와 네이밍 기준이 안정되어 있을 때 쓰는 편이 좋다.
typeHandlers와 plugins도 전역 설정이다
특정 Java 타입과 DB 타입 변환을 직접 다루거나, MyBatis 실행 과정에 플러그인을 끼워 넣는 설정도 mybatis-config.xml 쪽에 둔다.
<configuration>
<typeHandlers>
<typeHandler handler="com.example.mybatis.YnBooleanTypeHandler"/>
</typeHandlers>
</configuration>
이런 설정은 특정 Mapper 하나의 SQL 문제가 아니라 애플리케이션 전체의 타입 처리 기준에 가깝다. 그래서 Mapper XML에 흩뿌리지 않고 전역 설정으로 모으는 것이 낫다.
실무 팁: 여러 Mapper에서 반복해서 필요한 동작이면 mybatis-config.xml 후보이고, 특정 SQL 하나에만 필요한 조건이면 Mapper XML 후보로 보면 된다.
Mapper XML에는 무엇을 쓰나
SQL 문장과 namespace를 둔다
Mapper XML은 실제 SQL을 담는 파일이다. 보통 Mapper 인터페이스와 namespace를 맞춰 연결한다.
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUser" parameterType="String" resultType="User">
SELECT user_id, user_name
FROM users
WHERE user_id = #{userId}
</select>
</mapper>
여기서 namespace는 Mapper 인터페이스의 전체 경로와 맞추는 경우가 많다. id는 인터페이스 메서드명과 맞춘다. 이 둘이 어긋나면 MyBatis가 어떤 SQL을 실행해야 하는지 찾지 못한다.
Mapper 인터페이스가 Bean으로 잡히지 않는 문제와 XML namespace가 틀린 문제는 다르다. Bean 등록 문제는 스캔 설정을 먼저 보고, statement를 못 찾는 문제는 namespace와 XML 위치를 먼저 봐야 한다.
resultMap은 Mapper XML에 둔다
조회 결과와 Java 객체 필드 매핑이 단순하지 않다면 resultMap을 Mapper XML에 둔다.
<resultMap id="userResultMap" type="User">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="createdAt" column="created_at"/>
</resultMap>
<select id="selectUser" parameterType="String" resultMap="userResultMap">
SELECT user_id, user_name, created_at
FROM users
WHERE user_id = #{userId}
</select>
resultMap은 특정 조회 결과와 강하게 연결된다. 그래서 전역 설정 파일에 넣는 것이 아니라 해당 SQL이 있는 Mapper XML에 두는 편이 자연스럽다. 여러 SQL에서 공유할 수는 있지만, 그래도 Mapper XML 내부의 매핑 정의로 보는 것이 맞다.
동적 SQL은 Mapper XML의 책임이다
검색 조건에 따라 WHERE 조건이 달라지는 동적 SQL도 Mapper XML에 둔다.
<select id="searchUsers" parameterType="UserSearchCondition" resultType="User">
SELECT user_id, user_name
FROM users
WHERE 1 = 1
<if test="keyword != null and keyword != ''">
AND user_name LIKE '%' || #{keyword} || '%'
</if>
</select>
이런 SQL은 특정 업무 조회에 묶인다. 따라서 mybatis-config.xml에 넣을 성격이 아니다. config 파일에는 동적 SQL을 어떻게 쓸지의 규칙이 아니라, MyBatis 전체 동작 기준만 둔다고 보면 된다.
Spring에서는 두 파일을 어떻게 연결하나
Spring MyBatis 설정에서는 SqlSessionFactoryBean이 두 종류의 위치를 받아 연결한다. configLocation은 mybatis-config.xml 위치이고, mapperLocations는 Mapper XML 파일들의 위치다.
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setConfigLocation(
new PathMatchingResourcePatternResolver()
.getResource("classpath:/mybatis/mybatis-config.xml")
);
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:/mapper/**/*.xml")
);
return factoryBean.getObject();
}
이 구조는 바로 전 글에서 다룬 SqlSessionFactory 생성 흐름과 연결된다. SqlSessionFactoryBean이 전역 설정과 Mapper XML을 읽어서 SQL 실행 환경을 만들고, 이후 Mapper 호출은 SqlSessionTemplate을 통해 실행된다. 전체 생명주기가 헷갈리면 연동 흐름에서 기본 구성을 같이 확인하면 좋다.
차이를 표로 정리하기
| 구분 | mybatis-config.xml | Mapper XML |
|---|---|---|
| 역할 | MyBatis 전역 설정 | 업무 SQL과 결과 매핑 |
| 주요 내용 | settings, typeAliases, typeHandlers, plugins | select, insert, update, delete, resultMap |
| 적용 범위 | 애플리케이션 전체 | 특정 Mapper 또는 업무 기능 |
| Spring 연결 | configLocation | mapperLocations |
| 오류 예시 | 전역 설정 미적용, alias 인식 실패 | statement not found, resultMap 오류 |
| 점검 기준 | 공통 동작인가? | 특정 SQL인가? |
실무에서 자주 나는 오류
Mapper XML 위치를 잘못 잡은 경우
가장 흔한 문제는 Mapper XML이 빌드 결과물에 포함되지 않거나, mapperLocations 경로가 실제 위치와 다른 경우다.
factoryBean.setMapperLocations(
resolver.getResources("classpath:/mapper/**/*.xml")
);
파일은 src/main/resources/mappers/ 아래 있는데 설정은 mapper로 되어 있으면 XML을 못 찾는다. 이 경우 Mapper 인터페이스는 Bean으로 잡혀도 실행 시점에 statement를 찾지 못할 수 있다.
namespace와 인터페이스 경로가 다른 경우
Mapper XML의 namespace가 인터페이스 경로와 다르면 연결이 깨진다.
<mapper namespace="com.example.mapper.UserMapper">
인터페이스가 com.example.user.UserMapper로 이동했는데 XML namespace를 그대로 두면 MyBatis는 메서드에 해당하는 SQL을 찾지 못한다. 패키지 구조를 바꾼 뒤에는 MapperScan뿐 아니라 XML namespace도 같이 확인해야 한다.
typeAlias가 적용되지 않는 경우
Mapper XML에서 resultType="User"를 썼는데 alias가 등록되지 않았다면 타입을 찾지 못한다.
<typeAliases>
<package name="com.example.domain"/>
</typeAliases>
패키지 경로가 틀렸거나 해당 클래스가 다른 모듈에 있으면 alias가 적용되지 않는다. 이 경우 Mapper XML에서 전체 클래스명을 써서 원인을 좁혀볼 수 있다.
자주 놓치는 원인: Mapper XML 오류처럼 보여도 실제로는 configLocation, mapperLocations, typeAliases 중 하나가 잘못되어 MyBatis가 파일이나 클래스를 찾지 못하는 경우가 많다.
설정 파일을 나누는 기준
실무에서는 아래 질문으로 나누면 된다.
- 여러 Mapper에 공통으로 적용되는가?
- 특정 SQL 문장에만 필요한가?
- Java 타입과 DB 타입 변환 기준인가?
- 결과 컬럼과 객체 필드 매핑인가?
- Spring에서 파일 위치를 읽는 설정인가?
공통 동작이면 mybatis-config.xml, 특정 SQL이면 Mapper XML이다. 파일 위치를 Spring에 알려주는 것은 Java Config 또는 XML Spring 설정의 책임이다. 즉, mapperLocations 자체는 mybatis-config.xml의 내용이라기보다 Spring이 SqlSessionFactoryBean에 전달하는 설정으로 보는 것이 정확하다.
실무에서 바로 쓰는 팁
- 전역 설정은 mybatis-config.xml에 모은다. settings, aliases, typeHandlers처럼 여러 Mapper가 공유하는 기준을 둔다.
- SQL은 Mapper XML에 둔다. select, insert, update, delete와 resultMap은 업무 Mapper 단위로 관리한다.
- 파일 위치 설정은 Spring 설정에서 확인한다. configLocation과 mapperLocations가 실제 리소스 경로와 맞는지 본다.
- statement not found는 namespace와 id를 먼저 본다. MapperScan 문제와 XML statement 문제를 구분해야 한다.
- 필드가 null이면 resultMap과 alias를 같이 본다. 전역 camelCase 설정만 믿고 넘어가지 않는다.
자주 묻는 질문
- Q. mybatis-config.xml과 Mapper XML의 가장 큰 차이는 무엇인가요? A. mybatis-config.xml은 MyBatis 전체 설정이고, Mapper XML은 실제 SQL과 결과 매핑을 담는 파일입니다.
- Q. SQL 문장은 mybatis-config.xml에 넣나요? A. 일반적으로 넣지 않습니다. SQL 문장은 Mapper XML의 select, insert, update, delete 태그에 둡니다.
- Q. typeAliases는 어디에 설정하나요? A. 보통 mybatis-config.xml에 전역으로 설정합니다. Spring 설정에서 별도 프로퍼티로 등록하는 방식도 있지만 역할은 전역 alias 등록입니다.
- Q. resultMap은 어디에 두는 것이 좋나요? A. 특정 SQL 결과 매핑과 연결되므로 Mapper XML에 두는 것이 일반적입니다.
- Q. Mapper XML을 못 찾는 오류는 어떤 설정을 봐야 하나요? A. Spring 설정의 mapperLocations, 실제 XML 위치, 빌드 결과물 포함 여부를 확인해야 합니다.
- Q. Mapper 인터페이스는 있는데 SQL을 못 찾는 이유는 무엇인가요? A. XML namespace와 인터페이스 경로가 다르거나, SQL id와 메서드명이 다르거나, Mapper XML이 로딩되지 않았을 가능성이 있습니다.
정리
mybatis-config.xml과 Mapper XML은 둘 다 MyBatis에서 쓰는 XML이지만 역할은 다르다. 전자는 전역 설정, 후자는 업무 SQL과 결과 매핑이다. 이 둘을 구분하면 설정 오류를 볼 때 어디부터 확인해야 하는지도 명확해진다.
Spring MyBatis에서는 SqlSessionFactoryBean이 configLocation으로 mybatis-config.xml을 읽고, mapperLocations로 Mapper XML을 읽는다. Mapper가 안 잡히는 문제, SQL을 못 찾는 문제, 결과 필드가 null인 문제는 각각 확인할 위치가 다르다.
MyBatis 설정 파일을 볼 때는 "공통 동작인가, 특정 SQL인가"를 먼저 나누면 어디에 무엇을 써야 하는지 대부분 정리된다.
'웹개발 > Mybatis' 카테고리의 다른 글
| MyBatis resultType resultMap 차이, JOIN과 1:N 매핑에서 선택 기준 (0) | 2026.07.09 |
|---|---|
| MyBatis #{} ${} 차이, SQL Injection과 Oracle 동적쿼리 기준 정리 (0) | 2026.07.08 |
| MyBatis SqlSessionFactory SqlSession 차이, 역할과 생명주기 정리 (0) | 2026.07.08 |
| @MapperScan 설정과 Mapper 인터페이스가 Bean으로 안 잡힐 때 확인할 부분 (0) | 2026.06.29 |
| Spring MyBatis 연동 설정 완전 정리 (Maven/Gradle) (0) | 2026.06.29 |