Published 2022. 5. 2. 23:15
728x90

연관관계 맵핑

  • toString(), lombok 무한 루프 주의
    • ex) Team - Member 연관관계가 있을 경우 Team.getMember.toString -> Member.getTeam.toString -> Team.getMember.toString -> Member.getTeam.toString -> Team.getMember.toString -> Member.getTeam.toString -> Team.getMember.toString -> Member.getTeam.toString -> 무한 반복됨
  • Json 생성 라이브러리
    • Controller에서 Entity 절대 반환 금지
      • 무한루프 발생 가능성
      • 엔티티 변경 시 API의 스펙 자체가 변경되어버림 (단순 값만 있는 DTO 변환 후 반환하는 방법 권장)
  • 연관관계의 주인은 외래 키의 위치를 기준으로 정해야 함

 

연관관계 맵핑 어노테이션 & 옵션 정리

  • 일대다 양방향 맵핑
/* Member.java */
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team

/* Team.java */
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();

 

  • 지연로딩
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team

@OneToMany, @ManyToMany는 기본 옵션값이 지연 로딩

 

  • 즉시로딩
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team

즉시 로딩은 JPQL에서 N+1 문제를 일으킨다

 

@ManyToOne, @OneToOne은 기본 옵션 값이 즉시 로딩

 

연관관계 편의 메서드

/* Member.java */
public void changeTeam(Team team) {

    // 중복 등록 방지
    if (this.team != null) {
    	team.getMembers().remove(this);
    }

    this.team = team;
    team.getMembers().add(this);
}

/* Team.java */
public void addMembers(Member member) {
    this.members.add(member);
    member.changeTeam(this);
}

 

CASCADE(영속성 전이)

  • 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들도 싶을 때
    (ex: 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장)
  • 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없음
    (엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐)
  • 옵션 종류
    • ALL: 모두 적용
    • PERSIST: 영속
    • REMOVE: 삭제
    • MERGE: 병합
    • REFRESH: REFRESH 
    • DETACH: DETAC
/* Order.java */
@OneToOne(fetch = FetchType.LAZY, cascade = ALL)
@JoinColumn(name = "DELIVERY_ID")
private Delivery delivery;

/* Delivery.java */
@OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)

 

고아 객체

  • 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로보고 삭제하는 기능
  • 참조하는 곳이 하나일 때 사용해야함! 
  • 특정 엔티티가 개인 소유할 때 사용
  • @OneToOne, @OneToMany만 가능
  • 개념적으로 부모를 제거하면 자식은 고아가 된다.
    (따라서 고아 객체 제거 기능을 활성화 하면, 부모를 제거 때 자식도 함께 제거된다.
    이것은 CascadeType.REMOVE처럼 동작한다)
/* OrderItem.java */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ORDER_ID")
private Order order;

/* Order.java */
@OneToMany(mappedBy = "order", cascade = ALL, orphanRemoval = true)
private List<OrderItem> orderItems = new ArrayList<>();

 

영속성 전이 + 고아 객체, 생명주기

  • CascadeType.ALL + orphanRemovel=true 
  • 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화, em.remove()로 제거
  • 두 옵션을 모두 활성화 하면 부모 엔티티를 통해서 자식의 생명 주기를 관리할 수 있음
  • 도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용

 

cascade(영속성 전이), 고아 객체 실무 사용 팁

  • 모든 연관관계를 지연 로딩으로 구현
    (@ManyToOne, @OneToOne은 기본이 즉시 로딩이므로 지연 로딩으로 변경)

 

 

728x90

'개발 지식 > JPA' 카테고리의 다른 글

Querydsl 기본 문법 정리  (0) 2023.08.19
H2 DB 최초 생성 시 not found 에러 처리  (0) 2022.08.09
복사했습니다!