Kotlin + JPA에서 FetchType.LAZY가 제대로 작동 안된다면?
728x90
반응형

⚠️ 경고 ⚠️

 

본 카테고리, Dev Memo는 필자가 깊게 다루기는 귀찮지만 궁금한 것들을 체험해보고 간단하게 기록을 남기는 공간입니다. 디버깅 노트, 써드파티 라이브러리 사용기, 버전 업데이트, 어이없는 실수, 오탈자 발견 등. 각종 시덥지 않은 내용이 들어 갈 수 있다는 점 참고바랍니다. (우헤헿)

 


연관관계로 엮여있는 엔티티를 조회했을 때, 분명히 FetchType.LAZY를 적용했음에도 연관관계의 모든 엔티티가 조회되는 상황을 볼 수 있다. 그럼 혹시 아래 경우인지 확인해보자.

  1. 코프링 (코틀린 + 스프링)
  2. JPA를 사용한다
  3. 연관관계에 지연로딩을 적용한다. (FetchType.LAZY)
// 예) @Entity class Product
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
var category: Category? = null,

 

위와 같은 경우에 Product 엔티티와 Category 엔티티, 모두 검색(select 쿼리)가 날라갈 수 있다. 지연로딩을 사용했는데 말이다. 중요한 포인트는 코틀린을 사용하고 있다는 것이다. 우아한형제들 기술블로그에서는 다음과 같이 설명하고 있다.

 

Hibernate의 가이드 문서를 참조하면 엔터티 클래스는 final일 수 있지만 lazy loading을 위한 프록시를 생성할 수 없다고 되어 있습니다. 코틀린의 클래스와 프로퍼티, 함수는 기본적으로 final 이며 상속이 불가능합니다. 상속하기 위해선 open 키워드를 사용해야 합니다. 또한 클래스에 open 키워드를 붙인다고 해당 클래스의 프로퍼티와 함수도 open 되는 것이 아니기 때문에 상속을 허용하는 프로퍼티와 함수에도 open 키워드를 추가로 붙여주어야 합니다. (spring boot kotlin tutorial 에서는 allopen 플러그인을 사용하라고 권장합니다.)

 

거의 솔루션이나 마찬가지의 설명이다. 실제로 allopen을 아래와 같이 적용하였다.

plugins {
    ...
    kotlin("plugin.allopen") version "1.5.10"
}

allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.Embeddable")
    annotation("javax.persistence.MappedSuperclass")
}

이렇게 사용시 Entity, Embeddable, MappedSuperclass 어노테이션으로 적용된 클래스는 final이 아닌 open 클래스로 적용된다. 그 이후 테스트를 하면 기대했던 지연로딩(타겟 엔티티만 조회됨)이 동작하는 것을 확인할 수 있다.

728x90
반응형