ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] intellij Spring boot + mybatis + gradle bindingExceptiion
    IT/JAVA | Spring 2022. 9. 9. 19:16

    최근 운영중인 서비스에서는 문제가 없지만 개발환경인 intellij 에서 mybatis bindingException이 발생하는 이슈에 대해 알아볼기회가 생겼다.

     

    분명 운영중엔 문제가 없이 동작하지만 로컬 개발환경인 intellij 에서는

    org.apache.ibatis.binding.bindingException : Parameter 'parameter name' not found. Available parameters are [arg1, arg0, param1, param2 ...

    이라는 오류가 발생했다.

     

    내용이 길어 블로그는 2개로 나눠서 작성한다.

    해당 블로그는 Exception이 발생하는 이유에 대해서 설명한다.

    같은 소스에서 운영환경과 개발환경의 exception발생 차이는 후속으로 다룬다.

     

    먼저 오류내용을 살펴보면 mybatis를 사용하면 mapper에서 parameter를 넘기면 xml파일 ( 실제 sql이 작성되어있음 ) 에서 쿼리에 binding하여 쿼리를 실행시키는데 parameter를 정상적으로 binding시키지 못해서 발생하는 에러이다.

     

    원인은 환경에 따라 여러가지가 있다.

    우선 mapper에서 parameter를 어떻게 세팅하는지 부터 확인해보자

     

    기본적으로 변수나 map 등의 key 를 sql에 binding한다.

     

    아래는 기본적이면서 개발자의 실수로 인해 발생하는 경우이다.

     

    기본적인 내용이기에 자세하게 다루지 않겠다.

     

    1. 변수를 나열, map, VO,DTO 등

    // mapper interface
    String getBindingBlog(String url, String name);
    
    or
    
    String getBindingBlog(map paramMap);
    
    or 
    
    String getBindingBlog(paramVO paramVO);

     

    <select id="getBindingBlog"...>
    	select full_url
        from blog
        where url = #{url} <- interface에서 넘긴 변수 명
        and name = #{name} <- interface에서 넘긴 변수 명
    </select>

    위의 경우는 #{} 의 name과 parameter의 name이 달라질경우 binding하지 못하여 Exception이 발생할 수 있다.

     

     

    여기서 변수를 나열하여 binding하려할때 위 예제처럼 쓰는 경우도 있지만 @Param annotation을 사용하는 경우가 있다.

    필자는 @Param을 사용하면서 예상치 못한 오류를 발견했다.

     

    위에서 설명했듯 운영환경에선 정상동작하지만 개발환경인 로컬의 intellij 에서는 bindingException이 발생하는 경우다.

     

    @Param은 아래와 같이 사용한다.

    // mapper interface
    String getBindingBlog(@Param("subUrl") String url, @Param("nm") String name);
    <select id="getBindingBlog"...>
    	select full_url
        from blog
        where url = #{subUrl} <- interface에서 @Param으로 세팅한 변수 명
        and name = #{nm} <- interface에서 @Param으로 세팅한 변수 명
    </select>

     

    @Param은 sql에 binding할 이름을 지정한다.

     

    @Param annotation은 2가지가 있으며 해당 Exception은 여기서 발생했다.

    1. org.springframework.data.repository.query.param

    2. org.apache.ibatis.annotations.param

     

    위 두 annotaion은 선언방식도 같고 같은 목적을 위해 동작하지만 동작방식에 차이가 있다.

     

    1. org.springframework.data.repository.query.param

     -> 이름이 아니라 arg0, arg1.... 혹은 param1, param2.... 와같은 순서로 binding한다.

    위 예제를 보면 url과 name이 순서대로 binding된다.

    <select id="getBindingBlog"...>
    	select full_url
        from blog
        where url = #{arg0} <- interface에서 @Param으로 세팅한 String url
        and name = #{arg1} <- interface에서 @Param으로 세팅한 String name
    </select>

    위의 일반적인 변수명을 binding하는 방식으로 작성하면 

    org.apache.ibatis.binding.bindingException : Parameter 'parameter name' not found. Available parameters are [arg1, arg0, param1, param2 ...

    exception이 발생한다.

     

    2. org.apache.ibatis.annotations.param

     -> 위의 예제와 같이 변수명으로 binding한다. 일반적으로 사용하것과 같은 방식이다.

    <select id="getBindingBlog"...>
    	select full_url
        from blog
        where url = #{subUrl} <- interface에서 @Param으로 세팅한 변수 명
        and name = #{nm} <- interface에서 @Param으로 세팅한 변수 명
    </select>

     

    위와 같이 org.springframework.data.repository.query.param 을 사용하면 오류가 발생한다. 

     

    하지만 gradle build를 이용하면 해당문제를 회피할 수 있다. 

     

    intellij 에서 build and run을 기본값인 gradle로 세팅하면 두 경우 모두 정상적으로 동작한다.

     

    gradle과 intellij의 build방식 차이로 인해 발생한다.

     

    어떠한 차이로 인하여 gradle에선 정상적으로 동작하는지 확인하지 못하였으나 gradle build를 사용하면 해당 문제를 회피할 수 있다.

     

    보통의 개발환경에선 속도가 빠른 intellij로 세팅해놓고 사용하기 때문에 로컬환경에선 오류가 발생한다.

     

    가장 좋은 방법은 두 방법을 잘 이해하고 사용하여 로컬과 배포환경 모두 동작하도록 하는것이겠다.

     

    어떠한 이유에서 gradle에선 org.springframework.data.repository.query.param anntation을 사용해도 bindingException이 발생하지 않는지 알고있는 분은 댓글로 알려주시길 바랍니다.

    댓글

Designed by Tistory.