Mybatis를 사용하여 코딩하다가 재미(?) 있는 오류가 나서 문제를 찾아보고 해결방법을 정리해봤습니다.
에러 메시지의 내용은 아래와 같습니다.
org.mybatis.spring.MyBatisSystemException: nested exception is
org.apache.ibatis.type.TypeException: Could not set parameters for mapping:
ParameterMapping{property='address', mode=IN, javaType=class java.lang.Object,
jdbcType=null, numericScale=null, resultMapId='null',
jdbcTypeName='null', expression='null'}.
Cause: org.apache.ibatis.type.TypeException:
Error setting null for parameter #6 with JdbcType OTHER .
Try setting a different JdbcType for this parameter or
a different jdbcTypeForNull configuration property.
Cause: java.sql.SQLException: 부적합한 열 유형: 1111
눈에 금방 띄는 오류 메시지가 '부적합한 열 유형: 1111'입니다.
실제로 위의 메시지에 에러의 원인과 해결책이 모두 나와 있습니다.
Null 값을 입력하면서 JdbcType을 다른 것으로 지정했기 때문에 org.apache.ibatis.type.TypeException 예외가 발생했고, 해결 방법은 이 파라미터에 다른 JdbcType을 설정하거나, Configuration 속성에 jdbcTypeForNull을 설정하라고 되어 있습니다.
해결 방법 #1
해당 칼럼에 Null 값이 넘어가지 않도록 코딩에 주의하면 됩니다.
저의 경우 해당 칼럼의 파라미터가 제대로 Mapping 되지 않아서 ibatis에서 Mapping을 할 수 없었습니다.
<HTML>의 <FORM>에서 주소 값을 전달하는 과정에서, VO객체는 address라고 되어 있지만, <FORM>에서 주소는 <input name='addr1'><input name='addr2'>의 두 개의 칼럼으로 나뉘어 있었습니다. 그래서 VO 값이 Mapping 되지 않아 addres 값만 NULL로 설정되어 넘어갔습니다.
// Spring AOP BEFORE Advise에서 Param값 추적 결과
//
[BEFORE] MemberDAO.insertMember
[args] MemberVO(id=test, pwd=1111, name=테스터, email=test@email.com,
zip_num=, address=null, phone=, useryn=null, regdate=null)
Spring에서 Command 객체로 VO 값을 자동으로 설정할 경우, <FORM>에서 값을 입력하지 않은 <INPUT>은 VO에 공백 문자열과 같이 넘어갑니다. 그런데 <FORM>에서 사용한 <INPUT>에서 name이 VO와 Mapping 되지 않는 경우는 null로 표시되었습니다.
public String joinAction(
@RequestParam(value = "addr1") String addr1,
@RequestParam(value = "addr2") String addr2,
MemberVO vo, Model model) {
// Form의 값을 결합하여 Setter로 Address를 설정
vo.setAddress(addr1+addr2);
memberSerivce.insertMember(vo);
model.addAttribute("id", vo.getId());
...
}
다른 방법도 있겠지만 Java 코딩에서는 자동으로 Mapping 되지 않는 값의 경우 코딩으로 처리해줍니다.
즉, VO에 값이 빠짐없이 전달되도록 하면 됩니다.
해결 방법 #2
<insert id="insertData">
INSERT INTO mytable (컬럼명)
VALUE(#{컬럼명, jdbcType=컬럼_데이터타입})
</insert>
두 번째 해결 방법은 해당 칼럼에 JdbcType을 명시하는 방법입니다.
mybatis mapping 파일(mapping.xml)에서 칼럼에 값을 입력할 때 NULL값일 경우 처리할 데이터베이스의 칼럼과 동일한 데이터 타입을 적어 줍니다.
<insert id="insertMember">
INSERT INTO member (id, pwd, name, email, zip_num, address, phone)
VALUES(#{id}, #{pwd}, #{name}, #{email}, #{zip_num},
#{address, JdbcType=VARCHAR}, #{phone})
</insert>
해결 방법 #3
<settings>
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
마지막 해결 방법은 mybatis 설정 파일에 Null 처리를 하도록 명시하면 됩니다.
이렇게 설정하면 parameter mapping이 되지 않고 넘어가더라도 DB에 null로 값을 입력하게 됩니다.
한 가지 주의할 점은 <settings> 섹션은 반드시 <typeAliases> 위에 입력해야 합니다.
mybatis에서는 configuration xml에서 각 항목의 순서가 오류를 일으킬 수 있으니 확인하고 순서대로 입력해야 합니다.
이클립스에서 에러의 내용은 위와 같이 나옵니다.
아마도 위에 나온 속성들의 순서대로 xml 파일을 작성해야 오류가 발생하지 않는 것으로 보입니다.
아마도 propertes는 settings 보다 먼저 나와야 오류가 나지 않을 것 같습니다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
<typeAliases>
<typeAlias type="com.ezen.biz.dto.MemberVO" alias="member"></typeAlias>
</typeAliases>
<mappers>
<mapper resource="mappings/member-mapping.xml" />
</mappers>
</configuration>
수정한 내용은 위와 같습니다.
순서에 유의하여 작성해줘야 합니다.
주의사항
해결방법 #2와 해결방법 #3을 함께 사용할 수는 없습니다.
두 가지 중 한 가지만 적용해야 하며, 함께 적용할 경우 오류가 발생합니다.
NULL값에 대해 직접적으로 관리하고 싶다면 해결방법 #2,그냥 편하게 NULL값에 대한 처리를 하고 싶다면 해결방법 #3번을 선택하여 적용하면 됩니다.
댓글