MyBatis의 @Mapper
[!warning] MyBatis의
@Mapper
는 DataMapper (e.g., mapstruct의 @Mapper) 와는 다르다. MyBatis@Mapper
는 sql <> 객체 mapping을 처리하는 역할이다. 이 글에서@Mapper
는 MyBatis@Mapper
를 지칭한다.
MyBatis @Mapper를 사용하는 경우에도 @Repository는 사용
- MyBatis에서 제공하는 @Mapper 는 sql mapper 의미를 지닌다.
- 따라서 layer는 아래와 같이 표현되어야 한다.
1
2
@Service ---> @Repository ---> @Mapper ----> mapper.xml || annotation-string
DAO sql mapping
- 관습적으로 @Repository와 @Mapper를 동일한 layer로 간주하는 경우가 많은데, 서로 다른 layer로 간주해야 한다.
- “dao와 mapper의 차이” 로 검색해보면, 마치 두 개념이 같은 추상화 수준이며 서로 양립 불가한 것 처럼 보이는 글도 많다.
- 양립 불가한 것 처럼 보이는 설명을 도식화 하면 아래와 같다. (Repository와 Mapper 둘 중 하나를 골라서 써라. 라는 뉘앙스로 보인다) ``` @Service —> @Repository —> mapper.xml sqlSession.select(“mapper.xml”) ㄴ 이는 엄밀히 말하면 layer 생략은 아니지만 그렇게 보일 수 있다.
@Service —> @Mapper —> mapper.xml ㄴ Repository layer가 생략됐다. 좋지 않다. ```
- 그러나 둘은 양립 불가한 개념이 아니라, 둘 다 사용해야 하는 별도의 layer다.
- Repository layer를 생략하는 것은 좋지 않다.
@Service
가@Mapper
를 직접 사용하는 케이스는 Repository layer에서 수행해야 하는, 쿼리로 숨길 수 없는 data structure, schema에 대한 추상화를 Service layer에서 수행해야 한다.
Repository layer & DTO는 아래와 같은 물음에 대한 해답이 된다.
- Repository
member_half_tbl
,member_the_other_half_tbl
가져 올 때는 join으로 간단하지만,insert/update/delete
할 때는? (굳이 프로시저 써야 할까?)- DTO를 사용한다면, Domain Model <> DTO 변환은? 비즈니스 관심사가 아닌데 Service layer에서 해야 할까?
- persistence io 객체인 DTO field에 대한 null check 등 validation은? 쿼리에서 하기는 껄끄럽고, Service에서 하자니 뭔가 안맞는 경우는?
- DTO
- 반대로 성능 때문에 join해야 하거나, join 하지 말아야 하는 경우는?
- 배치에서 N+1 select를 피하기 위해 여러 비즈니스 모델에 사용되는 데이터를 한 번에 가져와야 한다면?
- DTO가 없다면 query가 변경될 때 Domain Model도 변경되어야 한다
- 특히 DTO 없이 Domain Model인 Member를 그대로 사용해 persistence io 하는 경우 자주 보이는 안티패턴이 있는데, [
불완전한 member(반쪽) + 불완전한 member(나머지) = 완전한 member
] 를 만드는 케이스다. - 참고 )[MyBatis] 객체 안의 객체 매핑하기 (ResultMap과 DTO) 방법 사용해서 DTO를 xml 단의 ResultMap으로 숨기는 것도 가능하지만 역할은 거의 동일하다
참고
- [MyBatis] 객체 안의 객체 매핑하기 (ResultMap과 DTO)
- DTO 사용하는 것의 장점
- 이 글에서와 반대로, 1개의 select, DTO로 2개 이상의 Domain Model을 가져와야 하는 경우
This post is licensed under CC BY 4.0 by the author.