Home [JPA] 영속성 전이, 지연 로딩
Post
Cancel

[JPA] 영속성 전이, 지연 로딩

영속성 전이 (cascade)

  • 엔티티의 상태를 변경할 때 해당 엔티티와 연관된 엔티티의 상태 변화를 전파시키는 옵션
  • 부모는 One, 자식은 Many
  • 단일 엔티티에 완전히 종속적이고 부모 엔티티와 자식 엔티티의 라이프 사이클이 유사할 때 활용할 것

CASCADE 종류

  • PERSIST : 부모 엔티티가 영속화될 때 자식 엔티티도 영속화
  • MERGE : 부모 엔티티가 병합될 때 자식 엔티티도 병합
  • REMOVE : 부모 엔티티가 삭제될 때 자식 엔티티도 삭제
  • REFRESH : 부모 엔티티가 refresh되면 연관된 자식 엔티티도 refresh
  • DETACH : 부모 엔티티가 detach되면 연관된 자식 엔티티도 detach 상태로 변경
  • ALL : 부모 엔티티가 영속성 상태 변화를 자식 엔티티에 모두 전이

옵션 설정 방법

  • cascade = CascadeType.ALL
1
2
  @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
  private List<OrderItem> orderItems = new ArrayList<>();

고아 객체 제거

  • 고아 객체 : 부모 엔티티와 연관 관계가 끊어진 자식 엔티티이다.

  • 영속성 전이 기능과 같이 사용하면 부모 엔티티를 통해 자식의 생명 주기를 관리할 수 있다.

  • @OneToOne, @OneToMany 어노테이션에서 사용할 것

    • 고아 객체 제거 기능은 참조하는 곳이 하나일 때만 사용해야 한다. 다른 곳에서도 참조하고 있는 엔티티를 삭제하면 문제가 생길 수 있다.

옵션 추가 방법

  • orphanRemoval = true

    1
    2
    3
    
        @OneToMany(mappedBy = "order", cascade = CascadeType.ALL
                , orphanRemoval = true)
        private List<OrderItem> orderItems = new ArrayList<>();
    

Cascade REMOVE 옵션과 차이점

  • Cascade REMOVE : 부모 엔티티 삭제 시 연관된 자식 엔티티도 함께 삭제
  • orphanRemoval : 부모 엔티티에서 자식 엔티티를 삭제

지연 로딩

즉시 로딩

  • 엔티티를 조회할 때 연관된 엔티티를 함께 조회
  • 일대일, 다대일로 매핑할 경우 기본전략
1
2
3
4
5
6
7
8
9
10
11
    @Test
    @DisplayName("지연 로딩 테스트")
    public void lazyLoadingTest(){
        Order order = this.createOrder();
        Long orderItemId = order.getOrderItems().get(0).getId();
        em.flush();
        em.clear();
        OrderItem orderItem = orderItemRepository.findById(orderItemId)
                .orElseThrow(EntityNotFoundException::new);
        System.out.println("Order class : " + orderItem.getOrder().getClass());
    }
  • orderItem.getOrder().getClass() : orderItem 엔티티에 있는 order 객체의 클래스를 출력
    • 즉시 로딩할 경우 매핑된 엔티티를 함께 가지고 온다. (order_item, item, orders, member 테이블)
    • 작성하고 있는 비즈니스 로직에서 사용하지 않을 데이터도 들고 오는 것
    • 즉시 로딩은 실무에서 사용하기 힘들다.

지연 로딩

  • 옵션 사용 : FetchType.LAZY

    1
    2
    3
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "item_id")
        private Item item;
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
	@Test
    @DisplayName("지연 로딩 테스트")
    public void lazyLoadingTest(){
        Order order = this.createOrder();
        Long orderItemId = order.getOrderItems().get(0).getId();
        em.flush();
        em.clear();
        OrderItem orderItem = orderItemRepository.findById(orderItemId)
                .orElseThrow(EntityNotFoundException::new);
        System.out.println("Order class : " + orderItem.getOrder().getClass());
        System.out.println("===========================");
        orderItem.getOrder().getOrderDate();
        System.out.println("===========================");
    }
  • orderItem.getOrder().getClass() : orderItem 엔티티만 조회
    • Order 클래스 조회 결과 : HibernateProxy (프록시 객체)
    • 프록시 객체 : 실제로 사용되기 전까지 데이터 로딩을 하지 않고, 실제 사용 시점에 조회 쿼리문이 실행된다.

출처📎

백견불여일타 스프링 부터 쇼핑몰 프로젝트 with JPA

This post is licensed under CC BY 4.0 by the author.