JPA를 공부하는데 객체 지향적인 설계와 코드 재사용성을 높이기 위해 편의 메서드를 작성하던 중 추가적인 select 쿼리가 발생하는 문제를 확인하고 지연로딩 (LAZY)
과 즉시로딩 (EAGER)
에 대해 정리해보려고한다.
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);
}
}
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
부터 테스트 해보자.
위 코드를 살펴보면 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)
의 값을 출력하게 된다.
지연 로딩에 대해서 디버깅 하기 위해서 아래와 같이 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.LAZY
는 Order 테이블의 데이터만 조회한다.
즉, fetchType.LAZY로 설정되어있으면, 연관 객체를 함께 조인해서 가져오지 않는다는 것이다.
그렇다면 언제 연관관계를 조회할까 ?
바로 관계필드의 getter 메서드가 호출될 때 select 쿼리가 추가적으로 발생하게 된다.
실제로 log.info("users : {}", findOrder.getUser())
를 실행해보면, 정상적으로 쿼리가 실행되고, User 객체를 출력하게된다.