안녕하세요. 오늘은 MyBatis를 활용하던 도중 발생했던 에러에 대해서 공유하고자 합니다.
먼저 발생한 Exception은 postgresql 쪽에서 PSQLException으로 던지고
MyBatis 에 의해 Exception이 Wrapping 되어 가장 가까운 Exception은
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping:
이런 메시지로 노출되게 됩니다.
cause를 쫓아 가게되면 결국 PSQLException으로
Caused by: org.postgresql.util.PSQLException: The column index is out of range:
다음과 같은 에러가 나게 됩니다.
우선 제가 해당 에러가 발생했던 경위는
select *
from users
where id = #{id}
-- and user_name = #{user_name}
이런식으로 Mybatis XML에다가 작성을 하고 쿼리를 수행했기 때문인데요.
여기서 실제 postgresql 쪽으로 전달되는 쿼리문과 mybatis가 쿼리문을 완성하기 위한 바인딩 작업에서의 형상이 달라서 발생하는 이슈입니다.
mybatis는 해당 쿼리문의 #{} 기호를 보면서 파라미터 바인딩 작업을 하게 되는데요. 실제 쿼리문에서 주석 라인을 제외하고 예약어인 #{} 키워드로 쿼리의 바인딩할 변수의 인덱스 갯수를 셉니다.( 위 쿼리에서 mybatis 바인딩할 변수의 인덱스 갯수는 1개 입니다.) 하지만 mybatis의 인터페이스를 봤을때!
public interface UsersMapper {
User selectUser(@Param("id") String id, @Param("user_name") String user_name);
}
파라미터에는 id와 user_name의 값이 Null이 아닐때 발생합니다!
파라미터 배열은 2개의 값이 넘어왔는데 실제 mybatis가 만든 statement 쿼리문에는 바인딩할 값이 1개밖에 없기 때문입니다.(#{} 표현을 쓰기 때문에 PreparedStatement로 대체됩니다.)
사실 간단히 생각해보면 당연한 이야기긴한데
너무 단순하게 생각하고 쿼리를 동작시키려고 하다보니 이런 실수를 하게된 것 같습니다.