- JPA에서 엔티티를 조회할 때 연관된 ‘엔티티 조회 방법을 결정하는 전략’을 의미합니다. - javax.persistence.FetchType 패키지 내에 열거형(Eunm) 형태로 제공이 됩니다. - FetchType에는 FetchType.EAGER 타입으로 ‘즉시 로딩(Eager Loading)’ 전략과 FetchType.LAZY 타입으로 ‘지연 로딩(Lazy Loading)’ 전략이 있습니다.
- A라는 엔티티와 B라는 엔티티가 존재한다는 가정하였을때, 테이블 간의 관계(Join)에서 A 엔티티를 조회하였을 경우에 B 엔티티를 ‘함께 조회’할 것인지 아니면 ‘필요에 따라 조회할 것’인지 결정하는 데 사용이 됩니다.
💡 해당 예시의 엔티티 간의 관계
- UserEntity라는 tb_user 테이블과 OrderEntity라는 tb_order 테이블 간의 1 : N 관계를 형성하고 있습니다. 즉, 1개의 사용자는 여러개의 주문을 할 수 있다는 형태로 설계가 되어 있습니다.
- 이러한 관계는 FetchType에서는 UserEntity와 OrderEntity 간의 관계는 User 엔티티 기준으로 OneToMany 관계를 가집니다. 해당 관계에서 fetch 속성을 기반으로 FetchType.LAZY 속성값을 지정하였습니다. - 이 지연 로딩(Lazy Loading)의 관계에서는 UserEntity를 조회할 때 OrderEntity는 조회하지 않고 OrderEntity 데이터가 실제로 사용될때 해당 데이터를 조회합니다.
💡 즉시 로딩(Eager Loading) : FetchType.EAGER - 엔티티를 조회하는 방법을 정의하는 전략 중 하나로 테이블 간의 관계에서 ‘A라는 엔티티를 조회할 때 연관된 B라는 엔티티도 함께 조회하는 방식’을 의미합니다.
- 이러한 방식은 한번의 쿼리로 필요한 모든 데이터를 가져올 수 있으나 필요하지 않은 데이터까지 조회되어 성능 이슈가 발생할 수 있습니다. - 또한 즉시 로딩의 경우 연관된 ‘엔티티를 실제로 사용될 때 조회하는 방식’이므로 엔티티를 조회할 때 연관된 엔티티도 함께 조회하여 메모리에 로드합니다.
💡 사용예시 - 사용자 엔티티(User Entity) 내에 주문 엔티티(Order Entity)로 @OneToMany 관계로 연결이 되어있을 경우, 사용자 엔티티(User Entity)를 조회하는 경우 주문 엔티티(Order Entity)도 함께 조회되는 방식을 의미합니다.
💡 사용자 엔티티 - @OneToMany(fetch = FetchType.EAGER) 를 통해서 해당 엔티티를 조회하는 경우 OrderEntity 정보를 가져올 수 있도록 구성하였습니다. - 또한 mappedBy 속성을 통해 OrderEntity의 필드명을 참조하였습니다.
- @ManyToOne(fetch = FetchType.LAZY)를 통해서 해당 엔티티를 조회하는 경우 UserEntity 정보를 가져올 수 없도록 구성하였습니다. - 또한 @JoinColumn(name = "user_sq")를 통해 UserEntity의 키와 대응하도록 구성하였습니다.
- UserEntity는 즉시 로딩(FetchType.EAGER)으로 지정하여서 UserEntity를 호출하는 메서드만 불러도 아래와 같이 출력이 되었습니다. - 즉, @OneToMany인 UserEntity와 @ManyToOne인 OrderEntity의 조회 결과로는 LEFT JOIN이 되어서 UserEntity 값이 모두 출력되는 조회결과를 얻었습니다.
- @ManyToOne(fetch = FetchType.LAZY)를 통해서 해당 엔티티를 조회하는 경우 UserEntity 정보를 가져올 수 없도록 구성하였습니다. - 또한 @JoinColumn(name = "user_sq")를 통해 UserEntity의 키와 대응하도록 구성하였습니다.
- Subject(인터페이스), RealSubject(구현체), Proxy(대행자)로 구성이 되어 있습니다. - Subject는 RealSubject, Proxy에 대한 공통 인터페이스로 사용됩니다. - RealSubject의 일을 Proxy가 위임(Delegate) 받아서 처리를 수행합니다.
2. RealSubject(implements) → Subject(interace) - Subject라는 인터페이스의 구현체인 RealSubject 클래스는 비즈니스 로직이 포함되어 있습니다. - 클라이언트가 호출한 DoAction() 메서드의 구현 부분이 이 클래스에 포함되어 있습니다.
3. Proxy → Subject(interace) - Proxy는 RealSubject의 대리자(delegate) 역할을 합니다. 클라이언트가 메서드를 호출하면, Proxy는 필요에 따라 이 요청을 RealSubject에게 전달하거나, 결과를 반환하거나, 그 밖의 다양한 작업을 수행합니다. - 이를 통해 객체 생성 시점 제어, 접근 제어, 또는 부가적인 로직 추가 등의 작업을 수행할 수 있습니다.
✅ 결론적으로 Client는 Subject 인터페이스의 DoAction()이라는 메서드를 호출하였습니다. 해당 호출에서는 실제 객체를 이용하지 않기에(Lazy Loading) 이에 따르는 구현체인 RealSubject 클래스의 DoAction() 메서드가 수행되는 것이 아닌 Proxy가 이를 위임(Delgate) 받아서 DoAction()의 수행처리가 됩니다.
- 실제 객체를 대신하여 사용되는 객체를 의미합니다. 실제 객체와 같은 인터페이스를 가지고 있으므로, 실제 객체와 동일하게 사용될 수 있습니다.
- 실제 객체의 생성 시점을 제어하는 데 사용되며 이는 지연 로딩(Lazy Loading)의 핵심 원리입니다. 실제 객체가 필요하기 전까지 실제 객체의 생성을 지연하며, 실제 객체가 필요한 시점에 실제 객체를 생성하고 초기화합니다. - JPA에서는 엔티티를 프록시로 로딩하는 기능을 제공합니다. @ManyToOne, @OneToOne 등의 관계에서는 FetchType을 LAZY로 설정하면, 연관된 엔티티를 프록시 객체로 로딩하고, 실제 엔티티가 필요한 시점에 데이터베이스에서 조회합니다. - 프록시 객체를 이용함으로써, 실제 객체의 생성 시점을 제어하고, 불필요한 데이터베이스 조회를 줄여 성능을 향상할 수 있습니다.
- 클라이언트는 Member라는 엔티티를 ‘지연로딩(Lazy Loading)’으로 지정하였습니다. - Member라는 엔티티를 지연로딩으로 지정을 하게 되면 최초 로드 시 ‘실제 엔티티를 가져오는 것’이 아닌 ‘엔티티의 프락시(Proxy)’를 먼저 로드를 하게 됩니다. - 지연로딩으로 지정하면 프록시가 자동으로 생기며, ‘실제 객체가 필요하기 전’까지 ‘실제 객체의 생성을 지연하기’ 위해 사용됩니다.
💡 Proxy를 통해 실제 객체를 이용하는 방법 1. Client → MemberProxy - 클라이언트는 Member Entity를 지연로딩 형태로 구성하였기에 MemberProxy가 생성이 되었고, 클라이언트는 실제 객체를 사용하기 위해 getName()이라는 메서드를 호출합니다.