TokyoAJ

도쿄아재

SPRINGBOOT 2025.04.07

MyBatis XML 대신 어노테이션 Mapper만으로 개발할 수 있을까? – 실무 기준 장단점 정리

MyBatis는 전통적으로 SQL을 XML로 관리해왔습니다.

하지만 최근에는 개발자가 XML보다 Java 코드에 익숙하고,

간단한 쿼리는 Interface에 직접 어노테이션으로 작성하고자 하는 경우가 많습니다.


그렇다면 MyBatis XML 없이, Mapper 어노테이션만으로도 실무 개발이 가능할까요?

이 글에서는 어노테이션 기반 Mapper의 장단점, 적용 방법, 실무 적합성까지 모두 정리해보겠습니다.


어노테이션 기반 Mapper란?

MyBatis에서는 다음과 같은 어노테이션을 통해 SQL을 직접 Mapper 인터페이스에 작성할 수 있습니다:


  1. @Select
  2. @Insert
  3. @Update
  4. @Delete


예시:

@Mapper
public interface UserMapper {

@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);

@Insert("INSERT INTO user (username, email) VALUES (#{username}, #{email})")
void insertUser(User user);
}


어노테이션 Mapper의 장점

장점설명
빠른 개발단순한 SQL은 XML 없이 바로 작성 가능
IDE 자동 완성Java 코드에 작성하므로 IDE 지원이 좋음
한눈에 로직 확인Mapper 인터페이스만 봐도 SQL 확인 가능
유지보수 간편XML 파일을 따로 관리하지 않아도 됨



실전 적용 방법

1. @Mapper 어노테이션 선언

@Mapper
public interface ProductMapper {
...
}

또는 @MapperScan(basePackages = "com.example.mapper")으로 패키지 스캔


2. SQL 어노테이션 사용

@Select("SELECT * FROM product WHERE category = #{category}")
List<Product> findByCategory(String category);


3. 파라미터 여러 개일 때는 @Param 필수

@Select("SELECT * FROM user WHERE username = #{username} AND status = #{status}")
User findByUsernameAndStatus(@Param("username") String username, @Param("status") String status);


한계와 단점

단점설명
동적 SQL 작성 어려움<if>, <where> 같은 조건 분기 불가
SQL 길어지면 가독성 하락복잡한 쿼리는 Java 코드에 어울리지 않음
SQL 재사용 어려움XML처럼 SQL fragment(sql 태그) 정의 불가
유지보수 시 불편개발자마다 스타일 다르면 복잡해짐



실무 기준 언제 쓰고, 언제 쓰지 말아야 할까?

상황어노테이션 Mapper 사용?
단순한 단건 조회(OK) 사용 가능
단일 Insert, Update(OK) 사용 가능
복잡한 동적 조건 쿼리(NO) XML 권장
페이징, 정렬, 검색(NO) XML 권장
다중 테이블 조인 + DTO 매핑(NO) ResultMap 있는 XML 권장
재사용 가능한 SQL 쿼리(NO) sql fragment 사용 불가



추천 전략: 혼합 사용 (XML + 어노테이션)

가장 실용적인 방법은 두 방식을 상황에 맞게 혼용하는 것입니다.

전략 예시:

용도방식
단순 조회 / 단건 등록어노테이션
복잡 쿼리 / 조인 / 페이징XML
공통 조건 조립XML fragment 사용
테스트용 빠른 쿼리어노테이션



실무 예제 구조 제안

@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);

// XML에서 구현: selectUserListByCondition
List<User> selectUserListByCondition(UserSearchDto condition);
}


<!-- resources/mapper/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUserListByCondition" resultType="User">
SELECT * FROM user
<where>
<if test="username != null">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
</where>
ORDER BY created_at DESC
</select>
</mapper>



마무리

MyBatis는 매우 유연한 프레임워크입니다.

단순한 경우엔 어노테이션 기반 Mapper,

복잡한 경우엔 XML Mapper를 쓰는 혼합 전략이 실무에서는 가장 적합합니다.


무조건 한 방식만 고집하기보다는,

유지보수성과 가독성을 기준으로 상황에 맞는 선택을 해보세요.



댓글