[트러블슈팅] Method threw 'org.hibernate.LazyInitializationException' exception 발생

김강욱·2024년 4월 22일
0

Project-Evertrip

목록 보기
2/19

스프링 시큐리티와 JPA를 사용하여 로그인 관리를 하고 있는데 권한을 확인하는 단계에서 에러가 발생하였습니다.

Method threw 'org.hibernate.LazyInitializationException' exception. Cannot evaluate com.evertrip.member.entity.Role$HibernateProxy$JJcsUqH7.toString()

우선 시큐리티 설정에서 권한에 대한 설정은 아래와 같습니다.

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                         .requestMatchers("/role").hasAuthority("ADMIN")
                         .anyRequest().authenticated());


    }

/role url을 요청받았을 때 시큐리티는 해당 사용자의 권한이 ADMIN 인지 확인하여 아닐 시 403 Forbidden 에러를 반환하게 됩니다.


오류가 발생했을 만한 곳에 디버깅을 하여 살펴보았습니다.

스프링 시큐리티에서 권한 확인 작업을 위해 CustomDetails. getAuthorities()를 호출하여 사용자의 권한을 받아오게 됩니다.

이 과정에서 member.getRole()를 호출하는 시점에서 에러가 발생하였습니다.

현재 Member와 Role의 관계 설정에서 fetch Type을 Lazy로 선언하였기 때문에 member.getRole()의 시점에서 Role 엔티티가 없는 것이 당연했습니다.

JPA에서는 Hibernate 내부 라이브러리를 이용해서 프록시 객체를 생성하게 됩니다. 프록시 객체는 실제 참조 객체를 가지고 있지만 처음에는 null 값을 들고 있습니다.

프록시를 처리하기 전에 영속성 컨텍스트에 해당 pk를 가진 엔티티가 존재하는지 확인하고 없을 시에 프록시 객체를 넣어주고 있을 시엔 프록시가 아닌 실제 엔티티를 집어 넣어주는데, Lazy Loading으로 세팅해놨기 때문에 Role 프록시 객체는 실제 참조 객체를 가지고 있지 않은 상태가 됩니다.

해당 Role 엔티티의 프록시 객체에 접근하려 할 때 실제 Role 엔티티를 DB에 쿼리를 날려 가져오는 것으로 착각하고 있었지만 이는 트랜잭션 범위 밖에서 접근이 이루어지기 때문에 에러가 발생하는 것이었습니다.

그래서 member에서 role을 즉시 로딩으로 바꿔서 해결하게 되었습니다.

즉시 로딩은 해당 엔티티를 그 시점에서 사용하지 않더라도 조인해서 가져오기 때문에 기본적으로는 지연로딩(Lazy Loading)을 사용하는 것이 정형화되어있지만 회원 정보에는 권한이 필수로 필요하다고 판단하여서 즉시 로딩을 사용하여 문제를 해결하였습니다.

profile
TO BE DEVELOPER

0개의 댓글

관련 채용 정보