Hibernate LazyInitializationException 해결

LazyInitializationException


Hibernate를 이용하여 개발하다보면, 자주 늘 만나는 녀석이다.
이러한 현상이 발생하는 이유는 다음과 같다.


1. 조회 서비스가 Select를 위한 서비스 (트랜잭션이 걸린)에 조회 요청을 한다.
2. 조회 결과가 반환 되면서 트랜잭션 종료
    - 이때 Entity는 영속상태가 아니라, 준영속 상태로 빠진다.
    - 만약 EAGER 패치로 가져왔다면 Entity의 하위 Entity가 함께 가져왔을 것이다.
      그러나 Lazy로 가져온 경우라면 하위 엔터티는 존재하지 않는 상태임.
3. Lazy 로 가져온 데이터가 준 영속 상태에서 하위 엔터티를 조회하면 LazyInitializationException이 발생한다.


해결방법 :

1. Use Hibernate.initialize :
   Hibernate.initialize 를 이용하여 하위 엔터티를 초기화 한다.
   (여기서 초기화라는 것은 프록시에 해당 엔터티 객체들을 로드해 둔다는 의미이다.)

Hibernate.initialize(topics.getComents());

2. Use Join FETCH
    - JPQL에서 JOIN FETCH문법을 이용하여 한번에 조인 결과를 다 가져온다.
    - EAGER 패치 설정을 기본으로 걸어서 한번에 결과를 가져온다.

3. Use OpenSessionInViewFilter / OpenSessionInViewInteceptor
    - LazyInitializationException은 View에서 보통 많이 발생한다. 이러한 경우 SessionInViewFilter를 걸어서 필터단까지 영속성을 가지고 가거나, 더 짧게는 SessionInViewInterceptor를 걸어 핸들러 단까지만 영속성을 가지고 가는 방법이 있다.

    - 사용시 다음을 주의해야한다.
        - 의도하지 않은 DB변경이 발생하지 않도록 주의해야한다.
        - 성능에 문제를 일으킬 수 있다.

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

# 참고 : 
- 일반적으로 LazyInitializationException은 View를 그릴때 해당 문제가 발생한다.
- 만약 데이터 저장시 발생하는 문제라면, 혹은 서비스단에서 해당 데이터 조합을 미리 가져와서 뷰에대한 데이터를 만들어 줄 수 있다면, 트랜잭션을 Service단까지 올려서 처리하면 된다.

Share this

Related Posts

Previous
Next Post »