[JPA] 즉시로딩, 지연로딩

Woo Yong·2024년 3월 21일
1

JPA

목록 보기
5/7
post-thumbnail

JPA를 공부하는데 객체 지향적인 설계와 코드 재사용성을 높이기 위해 편의 메서드를 작성하던 중 추가적인 select 쿼리가 발생하는 문제를 확인하고 지연로딩 (LAZY)즉시로딩 (EAGER)에 대해 정리해보려고한다.

Users 엔티티

public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    @Builder.Default
    private List<Orders> orders = new ArrayList<>();

    public void 편의_메서드(Orders order){
        this.orders.add(order);
        order.setUser(this);
    }
}

Orders 엔티티

public class Orders {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    Users user ;

    public void 편의_메서드(Users user){
        user.getOrders().add(this);
        this.user = user;
    }
}

테스트 코드

@Test
@Transactional
public void lazyTest(){
    Users u1 = Users.builder().name("u1").build();
    Orders o1 = Orders.builder().name("o1").build();
    o1.편의_메서드(u1);
    orderDao.save(o1);

    em.clear();

    Orders findOrder = orderDao.findById(1L).get();
    log.info("users : {}", findOrder.getUser());
}

FetchType.EAGER 디버깅

우선 FetchType.EAGER 부터 테스트 해보자.
위 코드를 살펴보면 Orders 엔티티 관계필드를 살펴보면 fetch = FetchType.EAGER로 되어있다.


그리고 save메서드에 브레이킹을 걸고 호출된 쿼리를 살펴보자.

console에 출력된 쿼리문을 살펴보면 편의메서드를 통해 정상적으로 User와 Order 테이블에 각각 insert 쿼리가 발생한 것을 확인할 수 있다.

계속해서 디버깅을 진행해보자.

디버깅을 진행하다보면 Orders findOrder = orderDao.findById(1L).get()실행문에서 Orders 테이블과 Users 테이블을 Join한 데이터를 조회하는 것을 볼 수있다.

그리고 정상적으로 order.getUser : Users(id=1, name=u1)의 값을 출력하게 된다.

FetchType.LAZY 디버깅

지연 로딩에 대해서 디버깅 하기 위해서 아래와 같이 Orders의 관계 필드의 fetch 값을 FetchType.LAZY으로 변경하자.

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Users user ;

그리고 동일하게 save 메서드에 브레이킹을 걸고 디버깅을 진행해보자.
디버깅을 진행해보면 save 메서드 실행하면 fetchType.EAGER과 동일하게 User와 Order 테이블에 각각 insert 쿼리가 발생하게 된다.

하지만 orderDao.findById()를 호출하면 다른 결과를 확인할 수 있다.

fetchType.EAGER의 경우에는 User와 Order 테이블을 조인해서 데이터를 한번에 조회하지만, fetchType.LAZYOrder 테이블의 데이터만 조회한다.

즉, fetchType.LAZY로 설정되어있으면, 연관 객체를 함께 조인해서 가져오지 않는다는 것이다.

그렇다면 언제 연관관계를 조회할까 ?
바로 관계필드의 getter 메서드가 호출될 때 select 쿼리가 추가적으로 발생하게 된다.

실제로 log.info("users : {}", findOrder.getUser())를 실행해보면, 정상적으로 쿼리가 실행되고, User 객체를 출력하게된다.

profile
Back-End Developer

0개의 댓글

관련 채용 정보