JPA 거짓 연관 관계 맺기(프록시)

2025. 11. 22. 15:57·개발/JPA
반응형

 

동일한 테이블의 2개의 엔티티

회사 프로젝트에 아래 예시 코드와 유사한 코드가 존재한다.

@Table(name = "prod")
@Entity
class Prod(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @Column(name = "name")
    val name: String,

    @JoinColumn(name = "vendor_id")
    @ManyToOne(fetch = FetchType.LAZY)
    val vendor: Vendor,

    /**
     * 더 연관 관계가 있다고 가정
     */
)

@Table(name = "prod")
@Entity
class ProdForExternalSystem(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @Column(name = "name")
    val name: String,

    // @ManyToOne, @OneToOne 등 연관 관계를 제거하고 외래 키 값만 보유한다.
    @Column(name = "vendor_id")
    val vendorId: Long,
)

 

  • Prod 엔티티는 실제 비즈니스를 해결하기 위해서 적극적으로 사용하는 클래스
  • ProdForExternalSystem 엔티티는 배치를 통해 외부 시스템과 연동할 때 사용하는 클래스

두 클래스는 모두 공통적으로 같은 테이블인 prod를 보고 있다.

 

그런데 왜 이렇게 분리가 되어있을까?

 

코드 히스토리를 추적해보니 Prod에서 @ManyToOne, @OneToOne 등 연관 관계를 조회해서 배치에서 저장하는게 싫어, ProdForExternalSystem을 작성했다고 나온다.

 

테스트 코드로 예시를 작성해보았다.

 

실제로 조회 쿼리가 1번 실행된다.

그래서 아래와 같이 id를 직접 저장하는 로직이 탄생했다.

조회 쿼리는 실행되지 않는다.

코드에 대한 생각

실제로 하나의 테이블에서 2개의 엔티티 클래스를 작성하는 일은 실무에서 빈번하다.

제일 많이 들은 사례는 어드민 엔티티와 고객 엔티티를 분리하는 일이다.

 

위 코드처럼 동일한 테이블인데, 연동 엔티티와 비즈니스 엔티티를 분리하는 건 괜찮은 분리라고 생각한다.

단일 책임 원칙을 잘 지킨 느낌이랄까 ?!

 

그러나 코드 히스토리에 남은 것처럼 의도가 중요하다고 생각한다.

 

단순히 조회를 한 번하고 연관관계를 매핑 하는게 싫어서, 분리한 것이라면 다른 멋진 대안이 존재한다.

바로 JpaRepository 인터페이스의 getReferenceById 메서드를 사용하면 된다.

 

JpaRepository 인터페이스의 구현체인 SimpleJpaRepository의 getReferenceById를 보면 구현이 아래와 같다.

이 메서드는 JPA 프록시 객체를 반환하는 메서드다.

해당 메서드를 사용하면 DB 조회를 하지 않고, 프록시 객체를 반환해 연관관계 매핑을 조회 없이 진행할 수 있다.

 

실행 쿼리를 살펴보면 조회 쿼리가 안나간걸 볼 수 있다.

getReferenceById를 통한 프록시를 반환을 사용해 조회 쿼리 없이 연관 관계 매핑하는 법을 알아봤다.

 

회사 코드를 수정할지는 고민 중에 있다.

이렇게 역할에 따른 엔티티 클래스 분리는 괜찮지 않을까..?! 라는 생각이 문득 들었다. (의도와는 다르지만!)

 

이번 포스팅에서는 실행된 쿼리를 직접 눈으로 보며 검증을 진행했는데, 다음 포스팅에서는 실행된 쿼리를 검증하는 자동화된 테스트에 대해 알아보겠다.

 

 

반응형
'개발/JPA' 카테고리의 다른 글
  • @Version을 사용하지 않는데 ObjectOptimisticLockingFailureException 등장?!
  • 낙관적 락, 비관적 락, 네임드 락
  • Spring Bean으로 등록된 EntityManager
  • Spring Data JPA 정리
Debin
Debin
공부 기록을 남기며 게시글 리팩토링을 진행하는 블로그입니다.
  • Debin
    리팩토링하는 블로그
    Debin
  • 전체
    오늘
    어제
    • 분류 전체보기
      • DB
        • DB 기초
        • MySQL
        • SQL 튜닝
      • OS
      • Network
      • Git
      • 디지털콘텐츠기획
      • 소프트웨어공학
      • 코딩테스트
        • 프로그래머스
        • 백준
        • 인프런
      • 공부 일지
      • 독서
        • 클린코드
        • 일상 속 사물이 알려주는 웹 API 디자인
        • 토비의 스프링
        • 객체지향의 사실과 오해
        • 자바 잘 읽는 법
      • 기록 및 회고
      • Cloud
        • AWS
      • 개발
        • Java
        • Spring Core
        • Spring MVC
        • Spring DB
        • Spring Boot
        • Spring Security
        • Spring Batch
        • JPA
        • Test
        • Android
      • 대외활동
        • UMC SERVER
        • 카엔프 SW 아카데미
      • 프로젝트
      • Docker
      • Gradle
      • ELK
      • 실무 이야기
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

    • 본인 깃허브입니다!
  • 인기 글

  • 태그

    객체
    프록시
    AOP
    스프링
    스프링 부트
    도커
    JPA
    토비의 스프링
    Java
    컨테이너
    트랜잭션
    객체지향
    innodb
    데이터베이스
    리눅스
    AWS
    test
    spring mvc
    mysql
    운영체제
    자바
    ORM
    인덱스
    redis
    docker
    SQL
    코딩 #개발자 #노마드북클럽 #노개북
    container
    spring
    spring boot
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Debin
JPA 거짓 연관 관계 맺기(프록시)
상단으로

티스토리툴바