궤도

[Spring] @Transational을 붙였는데도 LazyInitializationException이 발생한다면? (To. Spring Security를 쓰는 누군가) 본문

💻 현생/📋 스터디

[Spring] @Transational을 붙였는데도 LazyInitializationException이 발생한다면? (To. Spring Security를 쓰는 누군가)

영이오 2021. 7. 27. 16:50

면적면적

 

열심히 개발을 하던 중...

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role

이런 에러가 발생했다.

 

이거 책에서 많이 본건데...지연로딩과 관련해서 생기는 문제이다.

영속성 컨텍스트가 종료된 상태에서 다시 조회를 하려해서 발생하는 문제인데...

 

가장 간단한 해결방법은 fetch = FetchType.LAZY를 fetch = FetchType.EAGER로 바꾸는 것이다.

하지만 디폴트 값인 EAGER를 왜 굳이 LAZY로 바꿨겠는가?

 

EAGER로 하면 처음 조회시 연결되어 있는 모든 테이블을 함께 조회해서 성능이 떨어진다.

그러니 이 방법은 쓰지 못한다.

 

검색을 해보니 코드에 @Transational을 붙이지 않아서 생기는 문제라고 하는데...

이미 다 붙여놨었다.

 

근데 이상한 점은 바로

테스트가 전부 통과했었단 것이다.

 

그러다 한가지가 떠올랐다. 이 테스트는 서비스단에서 작성한 것인데, 그렇다면 컨트롤러의 문제가 아닐까??

그리고 깨달았다. 서비스단과 컨트롤러단의 거의 유일한 차이는

바로 이것. @AuthenticationPrincipal 어노테이션의 유무였다. 그렇다면 이유는 모르겠지만 얘가 문제가 아닐까?

그래서 관련 키워드로 구글링을 하자마자 찾았다!

 

Entity Lifecycle을 고려해 코드를 작성하자 1편

Entity Lifecycle을 고려해 코드를 작성하자 2편

아주 좋은 글이다.

 

아직 배움이 부족해서 제대로 이해하진 못했지만, 영속성 컨텍스트가 주입되기 전에 이미 @AuthenticationPrincipal을 통해 가져온 user 객체가 준영속화되기 때문에 이러한 오류가 발생하는 것이라고 한다.

 

src/main/java/jpa/myunjuk/infra/config/OpenEntityManagerConfig.java

package jpa.myunjuk.infra.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.stereotype.Component;

@Component
@Configuration
public class OpenEntityManagerConfig {

    @Bean
    public FilterRegistrationBean<OpenEntityManagerInViewFilter> openEntityManagerInViewFilter() {
        FilterRegistrationBean<OpenEntityManagerInViewFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new OpenEntityManagerInViewFilter());
        filterFilterRegistrationBean.setOrder(Integer.MIN_VALUE); // 예시를 위해 최우선 순위로 Filter 등록
        return filterFilterRegistrationBean;
    }
}

그래서 블로그대로 OSIV의 우선순위를 바꿔줬더니 이제 잘된다!

 

만약 테스트코드를 작성하지 않았다면 계속 서비스단에서 문제를 찾으려고 했을 것이다.

테스트코드의 중요성을 알게 됐고 배움에는 정말 끝이 없다. (물론 난 아직 기어다니는 수준이지만)

Comments