sggnology
하늘속에서IT
sggnology
전체 방문자
오늘
어제
  • 분류 전체보기 (83)
    • Algorithm (31)
      • Programmers (27)
      • Baekjoon (4)
    • WIKI (4)
      • VirtualBox (1)
      • Power Toys (1)
    • NodeJS (4)
      • nvm (1)
      • React (1)
      • Vue (1)
    • Dev Language (3)
      • Java (2)
      • Kotlin (1)
    • Spring Boot (17)
      • Gradle (1)
      • JPA (3)
    • DB (4)
      • MariaDB (3)
      • Redis (0)
    • Android (6)
      • Debug (3)
    • Nginx (3)
      • Debug (1)
    • Intellij (0)
    • Network (1)
    • Git (2)
      • GitHub (2)
    • Chrome Extension (0)
    • ETC (5)
      • Monitoring (2)
    • Linux (1)
      • WSL (1)
    • Visual Studio (1)
    • Side Project (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • mariadb
  • kotlin
  • 레벨3
  • nginx
  • Android Studio
  • docker
  • 레벨2
  • 프로그래머스
  • DB
  • 백준
  • 연습문제
  • 오블완
  • 알고리즘
  • java
  • 고득점KIT
  • 티스토리챌린지
  • 고득점 Kit
  • spring boot
  • JPA
  • 안드로이드 스튜디오

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
sggnology

하늘속에서IT

[JPA] hibernate bytecode enhancement 적용시 발생하는 오류 해결  (Failed to apply plugin 'org.hibernate.orm', gradle, kotlin)
Spring Boot/JPA

[JPA] hibernate bytecode enhancement 적용시 발생하는 오류 해결 (Failed to apply plugin 'org.hibernate.orm', gradle, kotlin)

2024. 5. 30. 17:22
728x90

발단

OneToOne 관계를 맺은 테이블에서 Lazy Initialization 을 의도하였으나 의도한 바대로 동작하지 않고 FetchType.Eager 처럼 동작하여 이를 해결하기 위해 적용한 bytecode enhancement plugin 이 찾을 수 없다는 이유로 적용되지 않는 이슈를 해결하는 과정입니다.

 

환경

  • Spring Boot 3.2.5
  • data-jpa-starter
    • hibernate-core 6.4.4.Final

 

OneToOne 사용시 FetchType.Lazy 가 의도대로 동작하지 않는 이유

 

[JPA] bytecode instrumentation 을 이용한 lazy loading 활성화-1

0. @OneToOne 의 양방향 연관 관계 다대일, 일대다, 다대다 와는 다르게 @OneToOne 매핑은 연관관계를 매핑할 수 있는 선택지가 두가지 있습니다. 아래와 같이 Post 와 PostDetail 엔티티가 있다고 생각해봅

sehyeona.tistory.com

 

 

동작하지 않는 이유에 대해 자세히 설명하는 글이 있어 참조하시면 더 정확한 이유를 아실 수 있을거라 생각합니다.

간단히 말해서 OneToOne 의 관계를 가지는 member 와 memebr_detail 테이블이 있다고 가정하겠습니다.

여기서 member_detail 에 외래키가 존재합니다. 이 때 member_detail 은 외래키를 통해 member 의 존재를 알고 있지만 member 는 member_detail 존재를 알지 못합니다.

여기서 정보의 간극이 발생하고 hibernate 정책에 따라 member 조회시 member_detail 에 대한 프록시를 생성하게 되는데 정보를 알기 위한 쿼리가 발생하여 FetchType.Lazy 가 적용되지 못하게 되는 겁니다.

 

문제 발생(build.gradle.kts)

plugins {
    id("org.springframework.boot") version "3.2.5"
    ..
    id("org.hibernate.orm") version "6.4.4.Final" // bytecode enhancement

    kotlin("jvm") version "1.9.23"
    ..
}
  • 위와 같이 plugin 을 kotlin("jvm").. 위에 선언하였지만 제목에서 언급한 오류가 발생하였습니다.
  • org.hibernate.orm 플러그인 버전이 맞지 않아서 인가 확인해보았지만 제가 사용중인 spring boot 의 jpa 버전에서는 6.4.4.Final 버전이 적용되어 있는것을 확인할 수 있었습니다.

 

순서가 문제였다

plugins {
    id("org.springframework.boot") version "3.2.5"
    id("io.spring.dependency-management") version "1.1.4"

    kotlin("jvm") version "1.9.23"
    ..

    id("org.hibernate.orm") version "6.4.4.Final" // bytecode enhancement
}
  • 위 코드에서 볼 수 있듯이 plugins 블럭의 가장 하위에 위치하니 정상적으로 동작하였습니다.
  • 정확히는 kotlin("jvm") .. 라인 하위에 있어야 plugin 을 적용할 수 있습니다.
  • plugins 블록 내부에서도 각각의 의존성이 그 순서에 맞게 배치되어있어 아무래도 org.hibernate.orm 의 경우 jvm 에 의존하고 있는 것으로 볼 수 있을거 같습니다.

설정

 

build.kotlin.kts

 

Hibernate ORM User Guide

Starting in 6.0, Hibernate allows to configure the default semantics of List without @OrderColumn via the hibernate.mapping.default_list_semantics setting. To switch to the more natural LIST semantics with an implicit order-column, set the setting to LIST.

docs.jboss.org

plugins {
    id("org.springframework.boot") version "3.2.5"
    ..

    kotlin("jvm") version "1.9.23"
    ..

    id("org.hibernate.orm") version "6.4.4.Final" // bytecode enhancement
}

// OneToOne 에서 lazy loading 을 지원하기 위한 설정입니다.
hibernate {
    // 블럭이 비었지만 이렇게라도 해놔야 설정된겁니다.
    enhancement {
        // 아래 4가지 요소가 설정된 겁니다.
        // enableLazyInitialization, enableDirtyTracking, enableAssociationManagement, enableExtendedEnhancement
    }
}
  • 위 링크는 hibernate 문서로 kotlin 이 아닌 java 에 대한 내용이지만 두 언어는 완전 호환되기에 무관하게 참조하였습니다.
  • 내용을 보면 hibernate.enhancement 를 재정의 하여 원하는 속성에 대해 값을 할당해주는 것을 볼 수 있습니다.
  • 그런데, enableLazyinitialzation 속성을 포함한 EnhancementSpec 클래스를 보면 setter 메서드가 deprecated 되어 있는 것을 알 수 있습니다.
  • 개별 조절을 하려면 argument 로 제공한다 명시되어 있어 세부 조정이 필요하지 않다면 위와 같이 작성하면 설정이 적용된 것 입니다.

 

Member, MemberDetailEntity 

// Member 테이블
@Entity
@Table(name = "member")
class MemberEntity (
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idx")
    var idx: Long = 0,

    ..
) {
    @OneToOne(mappedBy = "memberEntity", fetch = FetchType.LAZY)
    lateinit var memberDetailEntity: MemberDetailEntity
}

// Member Detail 테이블
@Entity
@Table(name = "member_entity")
class MemberDetailEntity (
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idx")
    var idx: Long = 0,

    @Column(name = "member_idx")
    var memberIdx: Int,
) {
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_idx", insertable = false, updatable = false)
    lateinit var memberEntity: MemberEntity
}

 

 

SQL 로그 확인

// bytecode enhancement 적용 X

Hibernate: 
    select
        me1_0.idx,
        ..
    from
        member me1_0 
    where
        me1_0.idx=?
Hibernate: 
    select
        mde1_0.idx,
        mde1_0.member_idx,
    from
        member_detail mde1_0 
    where
        mde1_0.member_idx=?


// bytecode enhancement 적용 O

Hibernate: 
    select
        me1_0.idx,
        ..
    from
        member me1_0 
    where
        me1_0.idx=?

 

728x90

'Spring Boot > JPA' 카테고리의 다른 글

[JPA] 테이블간의 연관관계 연결 실패(feat. cannot be cast to java.io.Serializable)  (0) 2024.06.11
[JPA] 연관관계를 맺은 객체에 대해 지연 로딩이 동작하지 않는다면(feat. kotlin, hibernate, lazy-loading)  (0) 2023.11.09
    'Spring Boot/JPA' 카테고리의 다른 글
    • [JPA] 테이블간의 연관관계 연결 실패(feat. cannot be cast to java.io.Serializable)
    • [JPA] 연관관계를 맺은 객체에 대해 지연 로딩이 동작하지 않는다면(feat. kotlin, hibernate, lazy-loading)
    sggnology
    sggnology
    하늘은 파란색이니까 내 삶도 파란색이길 ㅎㅎ

    티스토리툴바