wintertreey 님의 블로그

[MyBatis]1:N 객체 매핑 : <resultMap> <collection>, flatMap이란 본문

SQL과 DB

[MyBatis]1:N 객체 매핑 : <resultMap> <collection>, flatMap이란

wintertreey 2025. 9. 4. 18:57

<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