[JPA] @Embedded @Embedable 임베디드 타입이란?

2025. 5. 7. 09:13·BE/스프링부트와 JPA 활용
728x90

어제 스터디를 하면서 @Embedded는 "JPA에서 자주 사용하는 컬럼들을 모아둔 묶음"이라고 이해했다고 얘기했는데, 공부를 하며 틀린 부분이 있다는 걸 알게 되어 정리해본다. 결론적으로 말하면, @Embedded는 JPA가 미리 제공하는 내장 기능이 아니라, 개발자가 자주 사용하는 컬럼들을 직접 하나의 값 객체로 만들어서 재사용하는 방식이라고 이해하면 된다.

 

예를 들어 쇼핑몰을 생각해보자.

우리가 인터넷 쇼핑을 할 때 회원 정보에 "주소(Address)" 를 입력한다.

이 주소는 회원 정보(Member)뿐만 아니라, 주문(Order), 배송(Delivery) 정보에서도 사용될 수 있다.

이럴 때 매번 city, street, zipcode 필드를 반복해서 정의하기보다는 공통으로 사용하는 주소 구조를 @Embeddable 클래스로 묶어두고  필요한 곳에서 @Embedded로 포함시키면 유지보수도 쉽고 코드도 훨씬 깔끔하다.

@Embeddable
@Getter
public class Address {
    private String city;
    private String street;
    private String zipcode;

    protected Address(){

    }

    public Address(String city, String street, String zipcode){
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}
@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

}

Member 엔티티에서 주소를 @Embedded로 사용하면 “Member는 주소 정보를 포함한다”는 의미가 명확하게 드러나고, 재사용성도 좋아져 유지보수에 유리하다.

@Entity
@Getter @Setter
public class Delivery {

    @Id @GeneratedValue
    @Column(name = "delivery_id")
    private Long id;

    @OneToOne(mappedBy = "delivery")
    private Order order;

    @Embedded
    private Address adress;

    @Enumerated(EnumType.STRING)
    private DeliveryStatus deliveryStatus; // READY, COMP
}

Delivery도 마찬가지로 주소 정보가 필요하기 때문에 Address를 @Embedded로 재사용할 수 있다.
이 경우 DB에는 Delivery 테이블 안에 city, street, zipcode 컬럼으로 펼쳐진다.

 

컬럼으로 펼쳐진다는 말은 JOIN을 통해 별도의 테이블을 참조하는 것이 아니라 위 사진처럼

Address 클래스 안에 정의된 city, street, zipcode 등의 필드가 Member 테이블의 컬럼으로 직접 포함되어 저장된다는 의미다.

즉, @Embedded는 DB 설계 관점에서 봤을 때 테이블 간 관계를 만드는 것이 아니라 해당 엔티티의 일부처럼 데이터를 구성하는 것을 말한다.

 

근데, 문득 또 이런 생각이 들었다.

회원(Member)에 주소를 저장해둔다면 주문(Order)이나 배송(Delivery)에서 그걸 참조하면 되지 굳이 각자 Address를 가지는 이유가 뭘까?

주소는 시점마다 ‘복사되어 저장’돼야 하기 때문에, 공유하지 않고 각 엔티티에 @Embedded로 따로 저장한다.

 

예를들어

  • 회원 홍길동이 서울시 강남구에 살고 있음 → Member.address = 강남
  • 나중에 이 회원이 부산으로 이사함 → Member.address = 부산

그런데 과거의 주문 기록에서 주소는?

  • 배송 주소는 그 시점의 주소인 강남이어야 하는데,
  • Order.address가 Member.address를 참조하고 있었다면 이사한 순간 과거 주문 주소까지 부산으로 바뀌는 문제가 생긴다.

그래서 JPA에서는 주소를 참조하지 않고, 그 시점에 복사해서 박아두는 구조로 설계한다. Member, Order, Delivery는 Address를 "참조"하는게 아니라 그 당시의 Address를 @Embedded로 복사해서 저장하는 것!

 

앞으로 도메인을 분석하고 테이블을 설계할 때 이러한 부분도 함께 고려해야겠다는 생각이 들었다.

 

728x90

'BE > 스프링부트와 JPA 활용' 카테고리의 다른 글

[JPA] 2. 도메인 분석 설계 - 요구사항 분석 / 도메인 모델과 테이블 설계 / 엔티티 클래스 개발  (0) 2025.05.04
[JPA] 1. 프로젝트 환경설정  (0) 2025.05.04
'BE/스프링부트와 JPA 활용' 카테고리의 다른 글
  • [JPA] 2. 도메인 분석 설계 - 요구사항 분석 / 도메인 모델과 테이블 설계 / 엔티티 클래스 개발
  • [JPA] 1. 프로젝트 환경설정
DROPDEW
DROPDEW
💻 Developer | 기록하지 않으면 존재하지 않는다
  • DROPDEW
    제 2장 1막
    DROPDEW
  • 전체
    오늘
    어제
    • categories (401) N
      • App/Android (1)
      • BE (36) N
        • HTTP 웹 기본 지식 (8)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (12)
        • 스프링부트와 JPA 활용 (3) N
        • 스프링부트 시큐리티 & JWT (0)
        • PHP (6)
      • FE·Client (23)
        • HTML (1)
        • React (19)
        • Unity (1)
      • Data (12)
        • AI (4)
        • Bigdata (6)
        • Database (1)
        • 빅데이터분석기사 (0)
      • Infra (0)
      • CS (7)
        • CS 면접 준비 (3)
      • 취준 (13)
        • 자격증·인턴·교육 (4)
        • 인적성·NCS (6)
        • 코테·필기·면접 후기 (3)
      • 코테 (268)
        • Algorithm (220)
        • SQL (35)
        • 정리 (13)
      • 인사이트 (27)
        • 금융경제뉴스 (7)
        • 금융용어·지식 (2)
        • 북마크 (7)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    그리디알고리즘
    오블완
    그래프탐색
    매개변수탐색
    정렬
    다이나믹프로그래밍
    티스토리챌린지
    너비우선탐색
    최단경로
    그래프이론
    자료구조
    문자열
    백준
    브루트포스 알고리즘
    투포인터
    누적합
    구현
    이분탐색
    수학
    시뮬레이션
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
DROPDEW
[JPA] @Embedded @Embedable 임베디드 타입이란?
상단으로

티스토리툴바