Dandy Now!
  • [Spring Boot] 마이바티스(MyBatis) Parameter Not Found 에러 완벽 분석 및 해결: @Param 어노테이션 사용법
    2025년 04월 07일 17시 54분 48초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    마이바티스(MyBatis) Parameter Not Found 에러 완벽 분석 및 해결: @Param 어노테이션 사용법

    MyBatis는 강력하고 유연한 SQL 매퍼 프레임워크이지만, 개발 중 종종 org.apache.ibatis.binding.BindingException: Parameter '...' not found 와 같은 에러 메시지를 마주하게 된다. 특히 매퍼(Mapper) 인터페이스의 메소드에 두 개 이상의 파라미터를 전달할 때 자주 발생하는 이 문제의 원인을 명확히 파악하고, @Param 어노테이션을 이용한 깔끔한 해결 방법을 예제 코드와 함께 알아본다.

    1. 문제 상황 재현 (Error Scenario)

    사용자 상태(status)와 이름(name)을 조건으로 사용자를 조회하는 간단한 기능을 개발한다고 가정해보자.

    • DTO 예시 (UserDto.java)

      import lombok.Data;
      
      @Data
      public class UserDto {
          private String userId;
          private String userName;
          private String userStatus;
          // 기타 필드 ...
      }
    • Mapper 인터페이스 예시 (UserMapper.java) - 문제 발생 코드

      import java.util.List;
      
      public interface UserMapper {
          // 파라미터가 2개인데 @Param 어노테이션이 없음
          List<UserDto> findUsersByStatusAndName(String status, String name);
      }
    • Mapper XML 예시 (UserMapper.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="com.example.mapper.UserMapper"> // 네임스페이스는 실제 경로로
      
          <select id="findUsersByStatusAndName" resultType="com.example.dto.UserDto">
              SELECT user_id, user_name, user_status
              FROM users
              WHERE user_status = #{status} AND user_name LIKE CONCAT('%', #{name}, '%') </select>
      
      </mapper>
    • 예상 에러: 위 코드를 실행하면, MyBatis는 XML의 #{status}#{name}에 해당하는 파라미터를 찾지 못하고 다음과 유사한 에러를 발생시킨다.

      org.mybatis.binding.BindingException: Parameter 'status' not found. Available parameters are [arg1, arg0, param1, param2]

    2. 원인 분석 (Root Cause Analysis)

    • MyBatis의 파라미터 인식 방식:
      • 매퍼 인터페이스 메소드의 파라미터가 하나일 경우, MyBatis는 그 파라미터 자체를 인식하여 XML에서 어떤 이름(#{이름})을 사용하든 해당 파라미터의 값 또는 그 객체의 속성(property)에 접근한다.
      • 하지만 파라미터가 두 개 이상일 경우, MyBatis는 각 파라미터가 XML에서 어떤 이름으로 참조될지 알 수 없다. 따라서 명시적인 지시가 없으면 내부적으로 arg0, arg1, ... 또는 param1, param2, ... 와 같은 기본 이름을 부여한다. (arg0 또는 param1이 첫 번째 파라미터)
    • XML과의 불일치:
      • 개발자는 XML에서 #{status}, #{name}과 같이 의미 있는 이름을 사용하여 파라미터를 참조하려고 한다.
      • MyBatis가 인식하는 이름(arg0, arg1, ... )과 XML에서 사용하는 이름(status, name)이 다르기 때문에, MyBatis는 해당 이름의 파라미터를 찾을 수 없다는 BindingException을 발생시킨다.

    3. 해결 방법: @Param 어노테이션 사용 (Solution: Using @Param)

    • @Param 어노테이션: 이 문제를 해결하는 가장 명확하고 표준적인 방법은 org.apache.ibatis.annotations.Param 어노테이션을 사용하는 것이다. 이 어노테이션은 매퍼 인터페이스 메소드의 각 파라미터에 명시적인 이름을 부여하는 역할을 한다.

    • 적용 방법: 인터페이스 메소드의 각 파라미터 선언 앞에 @Param("XML에서 사용할 이름")을 추가한다.

    • Mapper 인터페이스 수정 예시 (UserMapper.java) - 해결된 코드

      import org.apache.ibatis.annotations.Param; // @Param 어노테이션 import
      import java.util.List;
      
      public interface UserMapper {
          // 각 파라미터에 @Param 어노테이션으로 이름 지정
          List<UserDto> findUsersByStatusAndName(
              @Param("status") String status,  // 'status' 이름 부여
              @Param("name") String name      // 'name' 이름 부여
          );
      }
    • 결과: 이렇게 수정하면, MyBatis는 status라는 이름의 파라미터 값과 name이라는 이름의 파라미터 값을 명확히 인식하게 된다. 따라서 XML에서 #{status}#{name}을 사용할 때 정상적으로 해당 파라미터 값으로 치환되어 SQL 쿼리가 실행된다.

    4. 추가 팁 (Additional Tips)

    • 단일 파라미터: 메소드 파라미터가 하나인 경우에는 @Param 어노테이션이 필수는 아니다. 하지만 파라미터가 Map이나 Collection 타입일 경우, 가독성이나 명확성을 위해 @Param을 사용하기도 한다.
    • 대소문자 구분: @Param 어노테이션에 지정한 이름(예: "status")과 XML에서 #{...} 안에 사용한 이름(예: status)은 대소문자를 포함하여 정확히 일치해야 한다.
    • DTO/Map 객체 사용: 파라미터가 매우 많아지는 경우, 각 파라미터에 @Param을 붙이는 대신 관련 파라미터들을 담는 DTO(Data Transfer Object)나 Map 객체 하나를 파라미터로 전달하는 방식도 고려할 수 있다. 이 경우 XML에서는 #{dto객체명.속성명} 또는 #{map키명} 형태로 접근하게 된다. (@Param 불필요)

    MyBatis에서 여러 파라미터를 매퍼 메소드에 전달해야 할 때는 @Param 어노테이션을 사용하여 각 파라미터의 이름을 명확히 지정해주는 것이 BindingException을 피하고 코드의 가독성을 높이는 좋은 습관이다.

    728x90
    반응형
    댓글