프록시
JPA에서 프록시는 객체를 지연 로딩하기 위해 사용된다. 프록시는 실제 객체 대신에 생성되며, 실제 데이터에 접근할 때 데이터베이스와 상호작용한다. 이를 통해 성능을 향상시키고 메모리 사용을 최적화할 수 있다.
프록시의 주요 특징:
지연 로딩(Lazy Loading): 프록시는 실제 데이터가 필요할 때만 데이터베이스에서 로드된다. 이를 통해 불필요한 데이터 로드를 피할 수 있다.
인터페이스 기반: JPA는 프록시 객체를 생성할 때, 해당 엔티티의 인터페이스를 구현한다. 따라서 프록시 객체는 실제 객체처럼 동작한다.
초기화: 프록시 객체는 실제 객체의 메소드에 접근할 때 초기화된다. 이 과정에서 데이터베이스 쿼리가 실행되어 필요한 데이터를 로드한다.
@OneToMany, @ManyToOne 관계: 이러한 관계에서 프록시를 자주 사용하여 관련된 엔티티를 지연 로딩할 수 있다.
프록시를 사용할 때 주의할 점은, 세션이 닫힌 후에는 프록시 객체가 초기화될 수 없으므로 LazyInitializationException이 발생할 수 있다. 이를 방지하기 위해서는 세션을 적절히 관리하거나 FetchType을 조정하는 것이 필요하다.
지연 로딩(Lazy Loading)
JPA에서 지연 로딩(Lazy Loading)은 성능을 최적화하기 위해 사용되는 기능으로, 필요한 데이터만을 실제로 요청할 때 로드하는 방식이다. 이 방법은 주로 관계형 데이터베이스에서 엔티티 간의 연관 관계를 처리할 때 사용된다.
필요할 때 로드: 지연 로딩은 실제로 해당 엔티티나 컬렉션에 접근할 때 데이터베이스에서 데이터를 가져온다. 초기에는 프록시 객체가 생성되어 메모리 사용을 줄인다.
프록시 객체: JPA는 지연 로딩을 위해 프록시 객체를 사용한다. 이 객체는 실제 엔티티의 인스턴스처럼 동작하지만, 필요한 경우에만 데이터베이스에서 실제 데이터를 가져온다.
관계 설정: @OneToMany, @ManyToOne, @ManyToMany 등의 관계에서 지연 로딩을 설정할 수 있다. 예를 들어, @OneToMany(fetch = FetchType.LAZY)와 같이 설정한다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private List<Order> orders;
// getters and setters
}
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
// getters and setters
}
세션 관리: 지연 로딩을 사용할 때, 데이터베이스 세션이 닫힌 후에 프록시 객체에 접근하면 LazyInitializationException이 발생할 수 있다. 이를 방지하기 위해서는 세션을 적절히 관리하거나, Eager Loading을 고려할 수 있다.
N+1 문제: 지연 로딩을 사용할 경우, 여러 엔티티를 조회할 때 N+1 쿼리 문제가 발생할 수 있다. 즉, 첫 번째 쿼리로 N개의 엔티티를 가져오고, 각 엔티티에 대해 추가 쿼리가 발생할 수 있다. 이를 해결하기 위해 JOIN FETCH를 사용할 수 있다.