본문 바로가기
JAVA & SPRING/JPA

JPA 기본편0 (연관관계 관리 즉시로딩과, 지연로딩)

by 눈오는1월 2024. 3. 4.
728x90

본 내용은 인프런 김영한 강사님 JPA 기본 편 강의를 듣고 정리한 내용입니다.

https://www.inflearn.com/course/ORM-JPA-Basic

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 강의 - 인프런

현업에서 실제로 JPA로 개발을 하고 있습니다. 그런 입장에서보면 지금 작성하고 있는 코드들이 어떻게 작동하는지 이해하는데 큰 도움을 주는 강의입니다. 다음은 제가 느낀 이 강의의 장점들

www.inflearn.com

 

이제 본격적으로 Member를 조회할 때 Team까지 조회할 필요가 없을 때 어떻게 해야 하는지 지연로딩을 배우면서 알아보자

 

지연로딩

연관된 엔티티를 사용하는 시점에서 조회가 발생하는 것을 말한다.

지연로딩 하는 방법은 연관관계 매핑에서 fetch를 LAZY로 정해주면된다. (아래에서 추후 다시 다룰 예정이다)

LAZY 설정

이렇게 하게 되면 member에서 팀을 가져와서 직접적으로 사용하기 전까지 Team은 프록시 객체로 되어있다.

지연로딩 코드
LAZY 코드 실행결과

위 결과처럼 Team을 직접적으로 사용하지 않기때문에 쿼리문을 보면 team에 관한 것은 조회되지 않고 Team 역시 프록시 객체로 출력되는 것을 알 수 있다.

LAZY를 이용한 지연로딩 실행
LAZY를 이용한 지연로딩 결과

위 결과에서 보이는 것과 같이 findMember.getTeam().getName()을 하는 순간 이때 select쿼리가 발생하고, teamA의 이름이 나오는 것을 알 수 있다.

 

만약 Member와 Team을 자주 함께 사용한다면

fetch = FetchType.EAGER로 바꿔주면 된다. (알고만 있으면 된다)

 

위와 같이 EAGER로 바꿔주는 방법을 즉시로딩 이라고 한다.

 

그러나 즉시로딩은 같이 자주 사용하게 되는 경우 이론상 유용하지만 실무에서는 반드시!!즉시로딩은 사용하지 않고 지연로딩만 사용해야 한다.

 

즉시로딩 주의점

1. 즉시 로딩을 적용하면 예상 하지 못한 SQL이 발생한다 -> 실제 협업에서는 수많은 테이블이 연관관계로 매핑되어 있는데 Member 하나 가져오는데 수십 개 테이블 조회가 발생할 수 있다.

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

3. @ManyToOne, @OnToOne은 기본이 즉시로딩 이기 때문에 반드시 LAZY로 바꿔줘야 한다. @OneToMany @ManyToMany는  기본이 지연로딩이다. 

 

즉시로딩 대신 JPQL fetch 조인이나 엔티티 그래프 기능을 이용하자!

 

영속성 전이(CASCADE)

특정 엔티티를 영속 상태로 만드는 과정에서 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용한다.

이때 주의해야 할 점은 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없고, 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함만 제공해 주는 것이다.

 

Parent 와 Child 관계

 

위 사진과 같이 Parent와 Child관계일 때 영속성 전이를 하지 않았을 경우 아래 코드와 같이 persist()를 3번 호출해야 한다.

persist() 3번 실행 코드
위 코드 실행 결과

 

영속성 전이를 사용하게 된다면 persist(parent)를 하면 자동으로 자식도 persist()가 된다.

 

영속성 전이 설정(ALL)
child persist() 주석처리
위 코드 실행결과

영속성 전이를 했기 때문에 child를 persist()를 하지 않고 parent만 persist()를 해도 child의 persist가 동작하는 것을 알 수 있다.

 

CASCADE의 종류로는 여러 가지가 있는데 그중에서 3가지만 확인해 보자

  • ALL: 모두 적용
  • PERSIST: 영속
  • REMOVE: 삭제(게시판 같은 하나에만 상속되어 있는 것만 해야 한다. 다른 테이블과 연결되어 있는 건 잘못 삭제하면 안 된다)

 

 

고아 객체

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제

orphanRemoval = true 이걸 사용하면 관련된 엔티티 역시 삭제된다.

orphanRemoval = true 적용
parent가 삭제될때 child도 삭제되는지 테스트하는 코드
위 코드 실행 결과

따로 remove()를 사용하지 않아도 child가 삭제되는 것을 볼 수 있다.

 

 

 

CascadeType.ALL + orphanRemoval=true

두 옵션을 모두 활성화해놓으면 부모 엔티티를 통해서 자식의 생명 주기를 관리할 수 있다.

이러한 방식은 도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용하다.

728x90