프록시
프록시 기초
em.find() vs em.getReference()
- em.find() : 데이터베이스를 통해서 실제 엔티티 객체 조회
- em.getReference() : 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회
프록시 특징
- 실제 클래스를 상속받아 만들어짐
- 실제 클래스와 겉 모양이 같다.
- 사용하는 입장에선 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 됨 (이론상)
- 프록시 객체는 실제 객체의 참조(target)을 보관
- 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출

- 프록시 객체는 처음 사용할 때 한번만 초기화한다. (그 이후엔 계속 가져다 씀)
- 프록시 객체를 초기화 할 때 프록시 객체를 통해서 실제 엔티티에 접근하는것이지 실제 엔티티로 바뀌는게 아니다.
- 프록시 객체는 원본 엔티티를 상속받기 때문에 타입 체크시 instanceof를 사용해야한다. (==는 false)
- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 getReference()를 호출해도 실제 엔티티를 반환한다.
(영속성 컨텍스트에 이미 엔티티가 있으면 당연히 프록시를 호출할 필요가 없음)
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생
(영속성 컨텍스트를 통해 실제 엔티티를 생성하는 것이기 때문이다.)
프록시 확인
- 프록시 인스턴스의 초기화 여부 확인 : em.PersistenceUnitUtil.isLoaded() 사용
- 프록시 클래스 확인 방법 : entity.getCLass().getName()
- 프록시 강제 초기화 : org.hibernate.Hibernate.initialize(entity);
(참고로 하이버네이트의 기능이다. JPA 표준은 강제 초기화가 없음)
지연로딩
Member를 조회할때 Team도 함께 조회해야 할까?
단순히 member 정보만 사용하는 비즈니스 로직이라면
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.LAZY) //**
@JoinColumn(name = "TEAM_ID")
private Team team;
..}

지연로딩을 사용했을 때, Member member = em.find(Member.Class, 1L); 를 호출할 경우
Team이라는 프록시 객체가 생성된다. (실제 엔티티가 아님)
Team 프록시 객체는 실제 team을 사용하는 시점, 즉 프록시 내부 값을 실제로 접근 하는 순간 DB조회가 일어나면서 프록시가 초기화된다.
이렇게 Member만 호출할 수 있고, 필요시에 Team을 호출하게 할 수 있다.
Member와 Team을 자주 함께 사용하는 경우? (비권장)
fetch = FetchType.EAGER를 사용하면 된다.
지연로딩과 반대로 member 조회시 항상 team도 함께 조회 쿼리가 나간다.
즉시로딩 주의점
- 예상치 못한 SQL이 발생할 수 있음
- JPQL에서 N+1 발생
- @ManyToOne, @OneToOne은 EAGER가 기본값이니 LAZY로 설정해줘야 함
결론 : 지연 로딩을 사용해라, fetch join이나 엔티티 그래프 기능을 사용할 것
영속성 전이 - CASCADE
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용한다.

위의 경우 em.persist(parent);, em.persist(child); 처럼 child를 일일이 영속화 시켜 줘야한다.
하지만 cascade를 사용하면 em.persist(parent);만 해줘도 같이 연결되어있는 child는 자동으로 영속화된다.

cascade는 연관관계를 매핑하는것과는 아무 관계가 없다.
엔티티 영속화 과정에서 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.
고아객체
orphanRemoval = true
- 고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
주의점
- 참조하는곳이 하나일 때 사용해야한다.
- 특정 엔티티가 개인 소유할 때만 사용할 것
- @OneToOne, @OneToMany만 가능하다.
영속성 전이 + 고아 객체, 생명주기
- CascadeType.ALL + orphanRemoval = true
스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화, em.remove()로 제거
- 두 옵션을 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
- DDD 설계시 유용함.
'JPA' 카테고리의 다른 글
| JPA의 값 타입 (0) | 2025.12.27 |
|---|---|
| 고급 매핑 - 상속 관계, Mapped Superclass (0) | 2025.12.25 |
| 엔티티 매핑, 연관관계 (0) | 2025.12.12 |
| 영속성 관리 - 내부 동작 방식 (0) | 2025.12.05 |
| 데이터 접근 기술 - JPA (0) | 2025.10.24 |