잡동사니

MyBatis에서 resultType으로 Object 맵핑시 필드에 상이한 값이 맵핑되는 이슈 본문

IT/Spring

MyBatis에서 resultType으로 Object 맵핑시 필드에 상이한 값이 맵핑되는 이슈

yeTi 2022. 5. 10. 17:35

안녕하세요. yeTi입니다.
오늘은 Mybatis를 사용하면서 결괏값을 받은 Object의 값이 상이하게 맵핑되는 현상을 해결한 내용을 공유하고자 합니다.

현상

MyBatis에서 sqlMapper를 활용하여 결괏값의 Object 맵핑 시 object의 필드에 예상과는 다른 값으로 맵핑되는 현상이 발견되었습니다.

Mapper.xml

<select id="..." resultType="com...TestEntity" parameterType="...">

TestEntity.java

@Getter  
@Setter  
@Builder  
public class TestEntity {  
    private Integer id;
    private String name;  
    private String nickname;  
    ...
}

Result

-- SQL 결과
id = 10
nickname = yeti
name = null

-- Instance 값
TestEntity.id = 10
TestEntity.name = "yeti"
TestEntity.nickname = "yeti"

원인

Mybatis를 사용하면 쿼리의 결과를 Object로 맵핑해주는 서비스가 동작합니다.

기본적으로 org.apache.ibatis.reflection.factory.DefaultObjectFactory 가 object를 생성하고, org.apache.ibatis.executor.resultset.DefaultResultSetHandler 가 결과를 맵핑해주는데요.

만일 ObjectNoArgsConstructor가 없이 AllArgsConstructor만 제공한다면 DefaultObjectFactoryAllArgsConstructor에 파라메터로 query의 결괏값을 맵핑해줍니다.

여기서 이슈가 발생하는데요.
파라메터를 맵핑하는 방식이 이름기반으로 하는게 아니라 쿼리의 결괏값의 순서로 하기 때문에 select 절의 컬럼의 순서와 Object의 필드의 순서가 일치하지 않으면 상이한 값이 object에 맵핑되는 문제가 존재합니다.

해결

디폴트 생성자를 만들어주면 됩니다.

TestEntity.java

@Getter  
@Setter  
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)  
@AllArgsConstructor
public class TestEntity {  
    private Integer id;
    private String name;  
    private String nickname;  
    ...
}

그렇게되면 DefaultObjectFactory 가 디폴트 생성자로 object를 생성하고, DefaultResultSetHandler 가 파라메터의 이름기반으로 결과를 맵핑해주기 때문에 해당 증상이 나타나지 않습니다.

Comments