[JPA] failed to lazily initialize a collection of role: could not initialize proxy - no Session

[JPA] Lazy Loading의 에러 LazyInitializationException 해결
Feb 22, 2024
[JPA] failed to lazily initialize a collection of role: could not initialize proxy - no Session
notion image
failed to lazily initialize a collection of role: could not initialize proxy - no Session
지연로딩으로 ~toMany를 불러오니 LazyInitializationException 가 떴다.
  • JPA에서 관리하는 세션이 종료된 후에 지연로딩이 생성하는 프록시(지연로딩은 즉시로딩과 달리 실제 엔터티 대신 프록시 엔터티 사용) 엔터티를 참조하려고 하니 초기화가 불가능해 지연로딩을 못하는 경우에 발생하는 에러
 
결론만 말하자면 난 UserService 클래스에 @Transactional(readOnly = true)을 써서 해결했다

1.@Transactional(readOnly = true)

@Transactional(readOnly = true) @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; . . 생략 . . }
영속상태에서 미리 연관관계 정보(질문엔터티, 답변엔터티)를 로드해두면 LAZY 에러 발생하지 않는다.

2. FetchType.EAGER - 지양

가장 단순한 방법으로는 FetchTypeEAGER로 설정해서 일괄적으로 질문 엔터티 호출할 때 답변 엔터티도 즉시로딩으로 초기화하도록 하면 되지만, 실무에서는 EAGER로 패치타입을 설정하는 것은 N+1 이슈 때문에 성능이 떨어져 매우 지양한다고 한다.
💡
EAGER로 설정해서 쿼리를 실행시켜 보면 유저는 여러명의 팔로잉, 팔로워, 질문을 가질 수 있고 질문은 또 답변을 가진다. 이것을 JPA를 이용하여 조회할 경우 실제 쿼리보다 N개의 쿼리를 더 조회화게 되는 N+1 이슈가 발생한다.

3. Fetch join

inner join으로 join한다. 그래서 N+1 이슈는 예방 가능 하지만 페이징 처리가 불가능하다는 단점이 있다. 난 페이징 기능을 사용 중이기 때문에 패스했다.
 

4. EntityGraph

EntityGraph 역시, EAGER 방식으로 연관관계를 가져온다. FetchType.EAGER 처럼 left outer join으로 데이터를 읽어오기 때문에, LazyInitializationException 에러를 해결 할 수 있다.
 

5. Open Session in View(OSIV) 패턴 활성화 - 지양

spring.jpa.open-in-view: true 을 글로벌 설정을 해줘서 오류를 해결할 수도 있다. 스프링 애플리케이션에서 영속성 컨텍스트를 HTTP 요청의 끝까지 유지하도록 하는 설정하는 옵션이다.
하지만 Session의 수명이 길어지기 때문에 권장되지 않는다.
 
 
Share article

silver0-stack