Framework/myBatis

[Mybatis] 쿼리 파라미터 null 처리방법

louis.dev 2013. 11. 14. 14:08
myBatis와 iBatis에서 쿼리를 실행할때 PrepareStatement 방식으로 작동을 하게 되고 이때 쿼리로 전달값은 값을 각각 아래처럼 적용한다.
<!-- ibatis 방식-->
<insert id="insertQuery" parameterType="java.util.Map">
	INSERT INTO table (id , name, title) VALUES (#id#, #name#, #title#)
</select>

<!-- mybatis 방식 -->
<insert id="insertQuery">
	INSERT INTO table (id , name, title) VALUES (#{id}, #{name}, #{title})
</insert>
그런데 이때 insert 하려는 값 중에 null이 전달되었을 경우 오라클에서는
uncategorized SQLException for SQL []; SQL state [99999]; error code [17004]; 부적합한 열 유형: 1111; nested exception is java.sql.SQLException: 부적합한 열 유형: 1111
이런 에러를 발생시키게 된다. Spring을 사용했을 경우는 이런에러를 발생시킨다.
Caused by: org.springframework.jdbc.UncategorizedSQLException: Error setting null parameter.  Most JDBC drivers require that the JdbcType must be specified for all nullable parameters. Cause: java.sql.SQLException : 부적합한 열 유형: 1111
그렇다고 항상 쿼리에서 null을 체크하는 방식을 사용하는것은 너무나도 귀찮은 일!! 그래서 if(myBatis)문 혹은 isNotEmpty(ibatis)를 사용하지 않는 방법이 있다. (자세히 보면 Spring Framework에서 발생시키는 에러에 답이있다.)  
<!-- ibatis 방식-->
<insert id="insertQuery" parameterType="java.util.Map">
	INSERT INTO table (id , name, title) VALUES (#id:VARCHAR#, #name:VARCHAR#, #title:VARCHAR#)
</insert>

<!-- mybatis 방식 -->
<insert id="insertQuery">
	INSERT INTO table (id , name, title) VALUES (#{id, jdbcType=VARCHAR}, #{name, jdbcType=VARCHAR}, #{title, jdbcType=VARCHAR})
</insert>
위와 같이 전달되는 파라미터 값의 jdbcType이 무엇인지를 정해 주면 쿼리는 자연스럽게 null로 변경되어 insert query가 수행된다.(물론 해당 column이 NULL값을 저장가능한 column 이어야 한다) 지원하는 jdbcType은 아래와 같다.
  1. BIT
  2. FLOAT
  3. CHAR
  4. TIMESTAMP
  5. OTHER
  6. UNDEFINED
  7. TINYINT
  8. REAL
  9. VARCHAR
  10. BINARY
  11. BLOB
  12. NVARCHAR
  13. SMALLINT
  14. DOUBLE
  15. LONGVARCHAR
  16. VARBINARY
  17. CLOB
  18. NCHAR
  19. INTEGER
  20. NUMERIC
  21. DATE
  22. LONGVARBINARY
  23. BOOLEAN
  24. NCLOB
  25. BIGINT
  26. DECIMAL
  27. TIME
  28. NULL
  29. CURSOR
쿼리마다 적당이 jdbcType을 지정해서 사용하자.