@Transactional이 붙지 않은 메서드 내에서 LazyLoading된 필드를 접근 시 하이버네이트가 LazyInitializationException을 발생시킨다.
왜냐하면 Lazy Loading이 동작하려면 영속성 컨텍스트가 필요하지만, 이게 닫혀있기 때문이다.
그럼 Hibernate는 어떻게 이를 알아챌까?
Lazy Loading의 동작과정
LazyLoading은 프록시 객체를 사용해서 동작한다.
특정 엔티티가 LazyLoading이 붙은 필드가 있다면, Hibernate는 이 엔티티의 프록시 객체를 생성한다.
class Room$HibernateProxy extends Room {
private List<Place> places = new PersistentBag(); // Lazy Loading Proxy
}
엔티티 자체를 프록시 객체로 만들고, LazyLoading이 붙었던 필드에 대해서 프록시 객체로 감싸 넣는다.
위 경우 places 필드는 실제 데이터를 데이터베이스에서 조회해오지 않는다.
이 후, places 필드를 조회하면 Hibernate는 PersistentBag을 통해 LazyLoading을 수행하려 한다.
Hibernate는 PersistentBag.initialize() 메서드를 호출하게 되며
public void initialize() {
if (!this.isInitialized()) {
// Hibernate Session이 활성화되어 있어야 함
if (session == null) {
throw new LazyInitializationException("no session");
}
this.loadFromDatabase(); // 데이터베이스에서 실제 데이터 가져오기
}
이 메서드는 다음과 같이 영속성 컨텍스트(세션)이 없으면 예외를 발생시키고, 있으면 조회해온다.
또한 내부적으로 PersistentBag.isInitialized()를 실행하여 이미 필드가 초기화되었는 지 확인한다.
public boolean isInitialized() {
return this.initialized; // 이미 로딩되었는지 확인
}
이미 로딩되었다면 기존 로딩된 필드를 제공한다.
'Spring > Spring Jpa' 카테고리의 다른 글
@ManyToMany를 사용하면 안 되는 이유 (0) | 2024.10.15 |
---|---|
OSIV란? (feat.OSIV를 통한 성능 최적화) (0) | 2024.09.25 |
Eager Loading(즉시 로딩) vs Lazy Loading(지연 로딩) 중 어느 전략을 사용해야 할까? (0) | 2024.09.24 |
spring jpa를 활용한 데이터 저장 성능 향상(saveAll(), bulk insert) (1) | 2024.05.16 |