본문 바로가기
데이터베이스 & ORM

JPA에서의 엔티티 참조 조회 방식

by DoRightting 2024. 7. 24.

JPA(Java Persistence API)에서 엔티티 간 관계를 맺고 있을 때, 참조값을 객체로 가지고 있는 엔티티를 조회하는 방식에 대해 설명합니다. 이는 데이터베이스 조회 성능과 애플리케이션의 동작에 중요한 영향을 미칩니다.

1. 즉시 로딩 (Eager Loading)

  • 정의: 엔티티를 조회할 때 연관된 엔티티도 함께 조회합니다.
  • 기본 적용: @ManyToOne, @OneToOne 관계
  • 장점: 연관 엔티티를 즉시 사용할 수 있습니다.
  • 단점: 불필요한 조인으로 인한 성능 저하가 발생할 수 있습니다.

2. 지연 로딩 (Lazy Loading)

  • 정의: 연관된 엔티티를 실제로 사용할 때 조회합니다.
  • 기본 적용: @OneToMany, @ManyToMany 관계
  • 장점: 필요한 시점에 데이터를 로드하여 초기 조회 성능을 개선할 수 있습니다.
  • 단점: 연관 엔티티 접근 시 추가 쿼리가 발생합니다.

3. 주요 개념

3.1 프록시 객체

  • 지연 로딩 시 실제 엔티티 대신 사용되는 가짜 객체입니다.
  • 실제 데이터가 필요할 때 데이터베이스에서 조회합니다.

3.2 N+1 문제

  • 연관된 엔티티를 개별적으로 조회하여 발생하는 성능 문제입니다.
  • 해결 방법: 페치 조인(Fetch Join), EntityGraph, BatchSize 등을 사용합니다.

3.3 영속성 컨텍스트

  • 1차 캐시를 통해 이미 로드된 엔티티를 재사용합니다.
  • 변경 감지(Dirty Checking)를 통해 엔티티의 상태 변화를 추적합니다.

4. 예제 코드

@Entity 
public class Order {

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long id; 
private String orderNumber; 

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "customer_id") 
private Customer customer; // getters and setters 
} 

@Entity 
public class Customer { 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long id; 
private String name; 
@OneToMany(mappedBy = "customer", fetch = FetchType.LAZY) 
private List<Order> orders; // getters and setters 
}
@Repository 
public class OrderRepository extends JpaRepository<Order, Long> { 

@Query("SELECT o FROM Order o JOIN FETCH o.customer WHERE o.id = :id") 
Order findOrderWithCustomer(@Param("id") Long id); 
}
@Service 
public class OrderService { 

	@Autowired 
	private OrderRepository orderRepository; 

	public void processOrder(Long orderId) { 
		Order order = orderRepository.findById(orderId).orElseThrow(); 
		System.out.println("Order Number: " + order.getOrderNumber()); // 지연 로딩 동작 
		System.out.println("Customer Name: " + order.getCustomer().getName()); 
		} 

	public void processOrderWithFetch(Long orderId) { 
		Order order = orderRepository.findOrderWithCustomer(orderId); 
		System.out.println("Order Number: " + order.getOrderNumber()); 
		System.out.println("Customer Name: " + order.getCustomer().getName()); 
		} 
}

5. 코드 설명

  • Order와 Customer 엔티티는 다대일(N:1) 관계를 가짐
  • @ManyToOne(fetch = FetchType.LAZY)로 지연 로딩 설정
  • OrderRepository의 findOrderWithCustomer 메소드는 페치 조인 사용
  • OrderService의 processOrder 메소드에서 지연 로딩 동작
  • processOrderWithFetch 메소드는 페치 조인을 통해 N+1 문제 해결

6. 결론

JPA에서 엔티티 참조 조회 방식은 애플리케이션의 성능과 동작에 큰 영향을 미칩니다. 즉시 로딩과 지연 로딩의 특성을 이해하고, 상황에 맞는 적절한 전략을 선택하는 것이 중요함. 또한, N+1 문제와 같은 성능 이슈에 대비하여 페치 조인 등의 최적화 기법을 적절히 활용해야 함.

'데이터베이스 & ORM' 카테고리의 다른 글

VACUUM ANALYZE  (1) 2024.11.11
PostgreSQL GIN  (5) 2024.11.10
QueryDSL 개요  (0) 2024.07.25
Q DTO  (0) 2024.07.21
Entity, Repository, DTO, domain, service의 연관성과 개념  (0) 2024.07.20