[JPA] 연관관계

Ceing·2026년 1월 5일

JPA

목록 보기
15/15
post-thumbnail

DB에서의 연관관계

  • DB에서는 외래키로서 각 테이블 간 관계를 연관관계로서 표현 가능
  • 외래키는 두 테이블 중 한 군데에서만 정의
  • N:1 관계일 경우 N쪽에 외래키가 위치됨

JPA에서의 연관관계

  • JPA에서는 참조(.)로서 각 객체 간 연관관계가 표현됨
  • 객체 그래프 탐색을 통해 각 연관관계에 접근 가능
    (member.getOrder().getOrderItem().getItem())
  • 연관관계 필드는 두 객체 중 어디서든 선언될 수 있음
  • 연관관계에 대한 CRUD 작업이 두 곳에서 일어나면 양방향으로 꼬일 수 있으므로 JPA는 한 객체에서만 외래키를 매핑해서 실제 CRUD 작업을 수행하게 하고 나머지 하나는 단순 연관관계에 대한 엔티티를 조회하는 역할만하게끔 함
  • 이때 연관관계를 실질적으로 관리하는 엔티티를 연관관계 주인이라고 칭함

연관관계 주인

  • 실질적으로 외래키를 매핑하며 연관관계에 대한 CRUD를 수행하는 주인 역할을 하는 엔티티를 연관관계 주인이라고 칭함
  • N:1 관계에서는 N에 해당되는 객체가 연관관계 주인 역할을 하고, 1:1 관계에서는 도메인과 비즈니스 로직을 분석 후 조금 더 적절한 엔티티가 연관관계 주인을 하게 됨
  • 만약 N:1 관계에서 1쪽이 연관관계 주인을 할 경우 국어적으로도 이상해지고 쓸데없는 쿼리가 DB로 flush되게 됨
  • 예를 들어 회원과 팀 관계에서 회원이 N이고 팀이 1인데 팀에 대한 정보를 수정했다고 회원에 대한 수정 쿼리가 나가는 것은 국어적으로 맞지 않음, 쿼리 성능적으로도 좋지 않게 됨
public class Member{
	@ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
	private Team team;
}


public class Team{
	@OneToOne(mappedBy = "team")
	private List<Member> members = new ArrayList<>();
}
  • N의 역할인 Member은 연관관계의 주인이므로 @ManyToOne를 통해 관계를 명시하고 @JoinColumn을 통해 어떤 외래키를 매핑하는지 지정해줄 수 있음
  • 1의 역할인 Team은 그저 매핑되는 객체이므로 주인인 Member 클래스의 team 변수에 매핑된다고 지정해줄 수 있음

다대다 관계

  • 객체는 컬렉션이 존재해서 다대다를 통해 각 연관관계를 표현 가능하지만, DB는 컬렉션 같은 도구가 없으므로 표현이 불가능함

  • 즉 JPA에선 표현이 가능해서 @ManyToMany가 있지만 DB에선 표현이 불가능하니 JPA의 @JoinTable을 통해 중간 테이블을 생성하게 해줘야됨

  • 해당 중간 테이블을 통해 일대다 다대일로 풀어낼 수 있음

public class Category{

  @ManyToMany
  @JoinTable(name = "category_item", joinColumns = @JoinColumn(name = "category_id"),inverseJoinColumns = @JoinColumn(name = "item_id"))
  private List<Item> items = new ArrayList<>();
}
  • 위와 같이 작성하면 category_id, item_id 외래키를 갖는 category_item이라는 중간 테이블이 생성됨

  • 하지만 치명적인 단점은 중간 테이블에는 다른 칼럼을 넣을 수 없이 오직 지정된 외래키 필드만 가질 수 있음, 간단한 등록일/수정일 조차도 넣지 못함

  • 즉 다대다일경우 처음부터 다대일, 일대다로 풀어야됨


셀프 양방향 연관관계

public class Category{
  /**
   * 셀프 양방향 연관관계
   */

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "parent_id")
  private Category parent;

  @OneToMany(mappedBy = "parent")
  private List<Category> child = new ArrayList<>();
}

셀프로 계층적으로 표현 가능

profile
이유에 대해 끊임없이 생각하고 고민하는 개발자

0개의 댓글