26/07/22 IL(I Learned) - MyBatis 2 (2)

Let's take a break·2026년 7월 27일

객체 관계 매핑(1:N)과 MyBatis resultMap 이해

이번 프로젝트에서 이전 MyBatis 프로젝트와 가장 큰 차이점은 하나의 테이블을 조회하는 것이 아니라 여러 테이블의 관계를 객체로 표현했다는 점이다.

이전 프로젝트에서는 하나의 Entity(Board, UserAccount)만 조회하여 화면에 출력하였다. 하지만 이번 프로젝트에서는 Member와 Order의 1:N 관계를 표현하기 위해 객체 참조와 resultMap을 활용하였다.

또한 관계형 데이터베이스의 Foreign Key를 Java에서는 객체로 표현하는 방식을 학습하면서 MyBatis의 객체 매핑 기능을 이해할 수 있었다.


1) Order 엔티티의 객체 참조

이전 프로젝트의 Entity는 하나의 테이블만 표현하였다.

이번 프로젝트에서는 Order가 Member를 참조하도록 설계되었다.


Order Entity

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class Order {

    private Long id;

    private String productName;

    private LocalDateTime orderDate;

    private Member member;
}

가장 큰 변화는

private Member member;

이다.

데이터베이스에서는

ORDER

member_id (FK)

만 저장되어 있다.

하지만 Java에서는

Order

↓

Member 객체

를 참조하도록 설계하였다.

즉,

DB에서는 FK 하나지만,

Java에서는 객체 하나가 연결되는 것이다.

이것이 객체지향적으로 관계를 표현하는 방법이다.


2) Controller에서 FK를 객체로 변환

주문을 저장할 때도 이전 프로젝트와 다른 방식을 사용한다.


OrderController

@PostMapping
public String insertOrder(
        @ModelAttribute Order order,
        @RequestParam Long memberId) {

    Member member = new Member();

    member.setId(memberId);

    order.setMember(member);

    orderService.insertOrder(order);

    return "redirect:/orders";
}

사용자가 선택하는 것은

memberId

하나이다.

하지만 Mapper는

Order

객체를 전달받아야 한다.

그래서

Member member = new Member();

member.setId(memberId);

를 이용하여 Member 객체를 생성한다.

그리고

order.setMember(member);

를 수행한다.

memberId

↓

Member 객체 생성

↓

Order.member 저장

↓

Mapper 전달

과정으로 변경된다.

이전 프로젝트에서는 단순한 DTO나 Entity만 전달했지만, 이번 프로젝트에서는 객체 안에 또 다른 객체를 포함하는 구조를 구현하였다.


3. MemberWithOrdersDTO

이번 프로젝트에서 가장 새롭게 등장한 DTO이다.


DTO

@Builder
public class MemberWithOrdersDTO {

    private Long id;

    private String name;

    private String email;

    private List<Order> orders
            = new ArrayList<>();
}

기존 DTO는

BoardViewDTO

↓

게시글 하나

또는

UserAccount

↓

사용자 한 명

처럼 하나의 객체만 표현하였다.

이번 DTO는

회원

↓

주문 목록(List<Order>)

을 하나의 객체 안에 저장한다.

예를 들어

홍길동

↓

노트북 주문

↓

키보드 주문

↓

마우스 주문

처럼

회원 하나가 여러 주문을 가지는 구조를 표현할 수 있다.


4) Service의 변화

이전 프로젝트에서는

findAll()

정도만 호출하였다.

이번 프로젝트에서는 관계 조회 기능이 추가되었다.

public List<MemberWithOrdersDTO> findAllMembersWithOrders() {

    return orderMapper.findAllMembersWithOrders();

}

Mapper가 반환하는 타입도

List<MemberWithOrdersDTO>

이다.

JOIN 결과

↓

DTO 생성

↓

Controller

로 전달된다.

이전 프로젝트보다 훨씬 복잡한 데이터를 한 번에 조회할 수 있게 되었다.


5) OrderMapper의 변화

기존 Mapper는

insert()

findAll()

findById()

update()

delete()

처럼 CRUD 메서드만 존재하였다.

이번 프로젝트에서는

List<MemberWithOrdersDTO>
findAllMembersWithOrders();

가 추가되었다.

이 메서드는 단순히 하나의 테이블을 조회하는 것이 아니라

MEMBER

JOIN

ORDER

결과를 하나의 DTO로 반환한다.

이를 위해 XML에서는 resultMap을 사용하여 부모 객체(Member)와 자식 객체(Order)를 연결한다.

resultMap을 사용하면 SQL의 JOIN 결과를 Java 객체 구조에 맞게 자동으로 매핑할 수 있어, 객체지향적인 데이터 처리가 가능해진다.


새롭게 배운 점

이전 MyBatis 프로젝트MyBatis2 프로젝트
단일 테이블 조회JOIN을 이용한 관계 조회
하나의 Entity 사용객체 안에 다른 객체 포함
단순 DTOMemberWithOrdersDTO를 통한 1:N 표현
CRUD 중심관계 매핑과 resultMap 활용
FK를 값으로 사용FK를 객체(Member)로 표현

느낀 점

이번 프로젝트를 통해 MyBatis는 단순히 SQL을 실행하는 프레임워크가 아니라 관계형 데이터베이스의 데이터를 객체지향 구조로 변환해 주는 역할도 수행한다는 점을 이해하게 되었다. 특히 Order 엔티티가 Member 객체를 참조하도록 설계하고, MemberWithOrdersDTO를 통해 회원과 주문 목록을 하나의 객체로 표현하는 과정을 학습하면서 객체 관계 매핑의 개념을 익힐 수 있었다.

검색, 정렬, 다중 삭제, 그리고 1:N 관계 매핑까지 구현하면서 MyBatis의 심화 기능과 실무에서 자주 사용되는 설계 방식을 경험할 수 있었다.

0개의 댓글