Post

[JPA #3] 즉시 로딩, 영속성 전이, 그리고 값 타입

[JPA #3] 즉시 로딩, 영속성 전이, 그리고 값 타입

주요 키워드

  • 프록시
  • 지연 로딩(Lazy loading)
  • 즉시 로딩(Eager loading)
  • 영속성 전이
  • 고아 객체
  • 임베디드 타입
  • 값 타입
  • 불변 객체

프록시

em.find() vs em.getReference()

  • em.find(): 실제 DB에서 엔티티 조회
  • em.getReference(): 프록시 객체 반환 (조회 지연)

프록시 객체의 특징

  • 실제 클래스를 상속받아 생성됨
  • 내부적으로 실제 객체를 참조(target)
  • 처음 사용할 때 한 번만 초기화됨
  • 초기화 후에도 프록시 객체는 그대로 유지됨
  • == 대신 instanceof로 타입 비교 필요
  • 영속성 컨텍스트에 이미 존재하면 실제 엔티티 반환
  • 준영속 상태에서 프록시 접근 시 오류 발생 가능 (LazyInitializationException)

프록시 관련 유틸

  • 초기화 여부 확인: PersistenceUnitUtil.isLoaded(entity)
  • 프록시 클래스 확인: entity.getClass().getName()
  • 강제 초기화: Hibernate.initialize(entity) 또는 member.getName()

즉시 로딩과 지연 로딩

  • 지연 로딩(LAZY): 프록시로 조회, 실제 사용 시점에 초기화
  • 즉시 로딩(EAGER): 조회 시 항상 연관된 엔티티까지 함께 조인 수행

주의사항

  • 모든 @~ToOne 관계에 지연 로딩 설정 권장 (특히 실무)
  • 즉시 로딩은 예기치 못한 SQL/N+1 문제 발생 가능
  • JPQL에서도 즉시 로딩은 문제 소지가 큼
  • @ManyToOne, @OneToOne 기본은 즉시 로딩 → LAZY로 설정 권장
  • @OneToMany, @ManyToMany는 기본이 지연 로딩

영속성 전이 (Cascade)

정의

  • 부모 엔티티를 영속화하면 자식 엔티티도 함께 영속화되도록 설정

특징

  • 연관관계 매핑과 무관
  • 부모가 자식의 생명주기를 관리할 때만 사용
  • 다른 곳에서 자식 엔티티를 공유한다면 사용 금지

고아 객체

  • 연관관계가 끊어진 자식 엔티티를 자동 삭제
  • orphanRemoval = true 사용
  • CascadeType.REMOVE와 유사
  • 참조하는 곳이 하나인 엔티티에만 사용

영속성 전이 + 고아 객체 = 생명주기 전이

  • em.persist()/em.remove() 없이 부모가 자식의 생명주기 완전 관리 가능
  • DDD의 Aggregate Root 구현 시 유용

값 타입

정의

  • int, String 같은 단순 타입 또는 임베디드 객체
  • 식별자가 없고, 변경 시 전체 교체 방식

값 타입 분류

  1. 기본 값 타입: int, double, String 등
  2. 임베디드 타입(복합 값 타입): @Embeddable 클래스
  3. 값 타입 컬렉션: @ElementCollection

임베디드 타입

  • 같은 테이블에 매핑됨
  • 객체와 테이블을 정밀하게 매핑 가능
  • 중첩 임베디드 타입 가능
  • 컬럼명이 중복될 경우 @AttributeOverride로 재정의 필요
  • 엔티티 간 값 타입 공유 금지 → 참조 공유 위험
  • 객체는 복사해서 사용하거나 불변 객체로 설계

불변 객체

  • 생성자만 제공하고 setter 미제공
  • 값 변경 불가 → 사이드 이펙트 예방
  • equals() 오버라이딩으로 동등성 비교

값 타입 컬렉션

  • 값 타입을 여러 개 저장할 때 사용
  • 별도 테이블 필요, 모든 컬럼을 묶어 PK 구성 필요
  • 기본적으로 지연 로딩 사용
  • 변경 시 전체 삭제 후 다시 저장 → 성능 이슈, 사용 주의
  • cascade + orphanRemoval 기본 적용

대안

  • 일대다 관계로 대체 + 영속성 전이 & 고아 객체 제거 조합
  • ex) AddressEntity

값 타입은 진짜 값 타입일 때만 사용하고, 식별자가 필요하거나 변경 추적이 필요하면 엔티티로 설계해야 한다.

This post is licensed under CC BY 4.0 by the author.