김영한 님의 "자바 ORM 표준 JPA 프로그래밍" 책을 정리한 포스팅 입니다.
1. 프록시
- 엔티티를 조회할 때, 연관된 엔티티를 항상 사용하는 것은 아닙니다.
- 모든 연관관계를 한꺼번에 가져오게 될 경우, 성능이 떨어질 수 있습니다.
프록시
항목 | 설명 |
목적 |
연관 엔티티를 실제 사용할 때까지 DB 조회를 지연(Lazy Loading)
|
프록시 객체 |
실제 클래스를 상속받아 만들어진 가짜 객체
실제 객체의 참조를 보관 - 프록시 객체의 메소드를 호출하면 실제 객체의 메소드를 호출 (데이터베이스 조회 지연 목적) |
초기화 | 영속성 컨텍스트에 의해 초기화됨 한 번만 초기화되고 재사용됨 내부에 실제 객체(target) 참조 |
식별자 활용 |
프록시는 식별자(ID)만 저장된 상태로 생성됨
식별자 접근은 초기화 없이 가능 ex) 상세 정보가 필요 없는 경우 ID만 참조해도 됨 → 프록시로 비용 절감 |
지연 로딩 예외 |
준영속 상태에서 초기화 요청 시 LazyInitializationException 발생
|
예시) 프록시 객체 생성
더보기
Member member = em.getReference(Member.class, "id1");
member.getName();
- 프록시 객체 반환 + 엔티티 객체 생성 X (DB 조회 X)
- (엔티티가 영속성 컨텍스트에 존재 시) 실제 엔티티 반환
예시) 프록시 확인
더보기
PersistenceUnitUtil().isLoaded()
boolean isLoad = em.getEntityManagerFactory().getPersistenceUnitUtil().isLad(entity);
- 프록시 인스턴스의 초기화 여부 확인
예제) 초기화 과정
더보기


class MemberProxy extends Member {
private Member target;
public String getName() {
if (target == null) {
// 2. 초기화 요청
// 3. DB 조회
// 4. 실제 엔티티 생성 및 참조 보관
this.target = ...;
}
return target.getName();
}
}
- 프록시 객체에 member.getName()을 호출하여 실제 데이터를 조회합니다.
- 실제 엔티티가 생성되어 있지 않으면, 영속성 컨텍스트에 실제 엔티티 생성을 요청합니다.
- 영속성 컨텍스트는 데이터베이스를 조회해서 실제 엔티티 객체를 생성합니다.
- 프록시 객체는 생성된 실제 엔티티 객체의 참조를 멤버변수에 저장합니다.
2. 즉시 로딩과 지연 로딩
항목 | 즉시 로딩 (FetchType.EAGER) |
지연 로딩 (FetchType.LAZY)
|
기본 동작 | 연관 엔티티를 즉시 함께 조회 |
연관 엔티티를 프록시로 조회
|
DB 조회 시점 | 엔티티 로딩과 동시에 연관 객체도 조회 |
연관 객체를 사용할 때 쿼리 실행
|
조인 전략 | ✅ (LEFT OUTER JOIN) | ❌ 사용 안함 |
@JoinColumn(nullable=false) | INNER JOIN | ❌ 사용 안함 |
프록시 사용 여부 | ❌ 사용 안함 |
✅
|
컬렉션 즉시 로딩 | LEFT OUTER JOIN ⚠️ 두 개 이상 즉시 로딩 금지 권장 → 성능 급락 (N+1 문제 발생 위험) |
❌ 사용 안함 |
LazyInitializationException | 발생하지 않음 |
❗ 영속성 컨텍스트 종료 상태에서 접근 시 발생 가능
|
성능 관점 | 불필요한 로딩 위험 → 성능 저하 가능 |
성능 최적화 유리 (필요 시만 조회)
|
예제) 즉시 로딩
더보기
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
private Team team;
// Member를 조회하면, Team도 함께 가져옴 (즉시 조인)
Member member = em.find(Member.class, 1L);
예제) 지연 로딩
더보기
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
Member member = em.find(Member.class, 1L); // team은 아직 조회 안 됨
Team team = member.getTeam(); // 이때 DB 조회 발생 (프록시 초기화)
4. 영속성 전이 : CASCADE
- 부모 엔티티를 영속 상태로 만들 때, 연관된 자식 엔티티도 함께 영속 상태로 만드는 기능
- 연관된 모든 엔티티는 영속 상태여야 함
- 수동으로 연관 엔티티까지 persist 하지 않아도 함께 영속화되는 편리함을 제공
항목 | 설명 |
적용 위치 |
@OneToMany, @ManyToOne, @OneToOne 등의 연관관계 매핑에 설정
|
대표 옵션 |
CascadeType.PERSIST: 부모를 영속화할 때, 연관된 자식들도 함께 영속화합니다.
CascadeType.REMOVE: 부모와 자식 엔티티 모두 제거하는 쿼리를 생성합니다. |
주의사항 |
연관된 모든 객체의 상태를 명확히 파악한 뒤 사용해야 함 (무분별하게 사용 시 데이터 무결성 문제 발생 가능)
|
예제
더보기
@Entity
public class Parent {
// ...
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<Child>();
}
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
고아 객체
- 부모 엔티티와 연관관계가 끊긴 자식 엔티티를 자동으로 삭제할 수 있습니다.
예제) @OneToMany의 orphanRemoval 속성
더보기
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<Child>();
...
}
'Spring > Spring Data JPA' 카테고리의 다른 글
[Spring Data JPA] 3-8. Repository query return types (0) | 2024.08.02 |
---|---|
[Spring Data JPA] 3-7. Repository query keywords (1) | 2024.08.02 |
[자바 ORM 표준 JPA 프로그래밍] 7. 고급 매핑 (2) | 2023.12.28 |
[자바 ORM 표준 JPA 프로그래밍] 6. 다양한 연관관계 매핑 (0) | 2023.12.27 |
[자바 ORM 표준 JPA 프로그래밍] 5. 연관관계 매핑 기초 (0) | 2023.12.27 |