wintertreey 님의 블로그
[MyBatis]1:N 객체 매핑 : <resultMap> <collection>, flatMap이란 본문
<resultMap> <collection>
1:N 관계를 객체 구조로 매핑할 때 사용된다.
Service에서 비즈니스 로직을 처리할 때 Map 안에 List<Map>의 구조를 이중으로 넣을 수도 있지만, <resultMap><collection>의 개념을 사용하면 mybatis xml 에서 쿼리상으로 한 번에 출력할 수 있다.
즉 이런 식으로 출력한다는 것.
{
"user_id": 1,
"user_name": "홍길동",
"order_list": [
{ "order_id": 101, "product": "노트북" },
{ "order_id": 102, "product": "키보드" }
]
}
이게 mybatis에서 쓰일 때의 모습이다.
<!-- User와 Orders 관계 매핑 -->
<resultMap id="getUserResult"
type="java.util.LinkedHashMap">
<collection property="order_list"
column="{user_id=user_idx}"
javaType="java.util.ArrayList"
select="getOrdersByUser"/>
</resultMap>
<!-- User 조회 -->
<select id="getUsers" resultMap="getUserResult">
SELECT U.user_idx,
U.user_name
FROM USERS U
</select>
<!-- Orders 조회 -->
<select id="getOrdersByUser" resultType="java.util.LinkedHashMap">
SELECT O.order_id,
O.product
FROM ORDERS O
WHERE O.user_id = #{user_id}
</select>
주의할 점
1. collection에서의 column 매핑 시
오른쪽 부모 쿼리(User 조회)에서 얻은 결과 칼럼(user_idx)를 읽어서,
왼쪽 자식 쿼리(Orders 조회)에서 사용할 파라미터 이름(user_id)로 전달한다는 뜻.
구분하기 위해 일부러 부모, 자식간의 칼럼명을 달리했지만, 기본적으론 같은 칼럼, 파라미터인게 좋다.
2.
자식 쿼리에서 #{user_id} 값을 바인딩하려면 부모 쿼리 결과에 반드시 user_id 칼럼이 존재해야한다.
그러니 API 설계문서에서 요구하는 Response data 형태에는 없다해도 조회해서 자식쿼리에게 넘겨주자!
사용 이유
그럼 이걸 비즈니스 로직단계인 Service 단에서 하지않고, MyBatis에서 하는게 좋을까?
List<User> users = userMapper.getUsers();
for(User u : users){
List<Order> orders = orderMapper.getOrdersByUser(u.getId());
u.setOrders(orders);
}
만약 Service에서 처리한다면, getUsers()로 유저만 조회한 후,
각 User마다 getOrdersByUser(userId)를 호출해서 루프를 돌려 List로 만들어 조립해야한다.
이렇게 되면 루프를 돌며 매번 DB를 조회하고, 쿼리가 엄청 많이 날라가게 된다.
XML에서 관계를 선언해두면, MyBatis가 알아서 한 번 의 조회 + 내부 조인으로 컬렉션 매핑을 하게 되고, 조회 및 조립을 MyBatis 레벨에서 해결하게 되어 Service 로직이 단순화되고 매핑 규칙이 명확해진다.
flatMap
map 은 상자 안에 상자를 넣는 구조. 즉 중첩구조가 생김.
flatMap은 상자 안의 상자를 열어서 한 줄로 만드는 구조를 말한다.
//javascript 예시
const arr = [[1, 2], [3, 4]];
// map → [ [2,4], [6,8] ]
console.log(arr.map(x => x.map(y => y * 2)));
// flatMap → [2,4,6,8]
console.log(arr.flatMap(x => x.map(y => y * 2)));
// java 예시
List<List<String>> list = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")
);
// map만 쓰면 → List<List<String>> 구조
List<List<String>> mapped = list.stream()
.map(l -> l) // 그냥 그대로 전달
.toList();
// flatMap 쓰면 → 평평해져서 List<String>
List<String> flatMapped = list.stream()
.flatMap(l -> l.stream())
.toList();
System.out.println(mapped); // [[A, B], [C, D]]
System.out.println(flatMapped); // [A, B, C, D]
'SQL과 DB' 카테고리의 다른 글
[MySQL] Transaction (0) | 2025.09.08 |
---|---|
[MySQL] Rename, JOIN (0) | 2025.09.04 |
[MySQL] UPDATE (0) | 2025.08.29 |
[MySQL] SELECT (2) | 2025.08.26 |
[MySQL] INSERT (0) | 2025.08.26 |