📚 TIL: JPA 연관관계 매핑 및 핵심 기능 정리
🔗 연관관계 매핑 (1:N, 1:1, N:M)
- 단방향: 외래키 보유한 엔티티만 참조 가능
- 양방향: 연관관계의 주인 설정 필수 (외래키 관리)
- 실무 권장: 항상 N:1 양방향을 우선 고려
🔸 1:N 단방향
- @OneToMany + @JoinColumn 사용 시 성능 이슈 (추가 UPDATE)
- 객체지향적으로는 자연스럽지만, DB 설계상 비효율적
🔸 1:N 양방향
- N:1 + @ManyToOne 사용 → 외래키는 N쪽
- 객체와 테이블 모두 자연스러운 구조
🔸 1:1 연관관계
- 외래키 위치 선택 가능 (UNIQUE 제약 필요)
- 설계 변경 유연성 고려 시 외래키는 조회 빈도가 높은 테이블에 둔다
🔸 N:M 연관관계
- 실무에서는 중간 엔티티로 분리해서 @OneToMany, @ManyToOne 구성
- 추가 필드(level, license) 필요할 수 있어 @ManyToMany는 지양
🧬 상속관계 매핑
- @Inheritance(strategy = …) + @DiscriminatorColumn
- 전략별 비교:
전략설명특징
| SINGLE_TABLE | 단일 테이블 | 빠른 조회, NULL 많음 |
| JOINED | 정규화된 테이블 | JOIN 발생, 성능 이슈 |
| TABLE_PER_CLASS | 각 자식 테이블 | 거의 사용 안 함 |
- 비즈니스 복잡 → JOINED, 단순/확장 적음 → SINGLE_TABLE
👻 프록시와 지연 로딩
- em.getReference() → 프록시 객체 반환 (조회 지연)
- 실제 값 사용 시점에 DB 조회 (초기화)
- 주의: 준영속 상태에서 접근 시 LazyInitializationException
🔸 로딩 전략
전략설명기본 위치
| LAZY | 지연 로딩 (프록시) | @OneToMany, @ManyToMany |
| EAGER | 즉시 로딩 (JOIN) | @ManyToOne, @OneToOne |
- 실무에서는 대부분 LAZY 사용 + Fetch Join/EntityGraph 활용
🔄 영속성 전이(Cascade) & 고아 객체
- Cascade: 부모 엔티티의 저장/삭제가 자식에게 전이
- 예: CascadeType.ALL, PERSIST, REMOVE
- 완전 종속된 관계에서만 사용
- 고아 객체: 부모와 관계 끊긴 자식 자동 삭제
- orphanRemoval = true 사용
- 하나의 부모만 참조할 때만 사용
🔁 트랜잭션 전파 (Propagation)
- 여러 트랜잭션 간 처리 방식 정의
- @Transactional(propagation = …) 사용
옵션설명
| REQUIRED | 기존 트랜잭션 참여 (기본값) |
| REQUIRES_NEW | 새 트랜잭션 시작, 기존 트랜잭션 중단 |
| NESTED | 중첩 트랜잭션 (부분 롤백 가능) |
| SUPPORTS, NOT_SUPPORTED, MANDATORY, NEVER 등도 존재 |
- 예: 포인트 지급 실패 시 회원가입은 성공 → REQUIRES_NEW 사용
💡 오늘의 인사이트
- 객체-테이블 설계 차이를 고려하여 연관관계 전략 선택이 중요
- N:M은 중간 엔티티로 풀어서 설계
- 프록시/로딩 전략은 성능과 설계 유연성에 직결됨
- 생명주기 전이는 일관된 제어가 필요 (Cascade, Orphan)
- 트랜잭션 전파 옵션은 복잡한 요구사항 대응에 핵심
'Spring' 카테고리의 다른 글
| TIL - Spring 심화 회고 (0) | 2025.04.21 |
|---|---|
| Test코드 트러블 슈팅 (0) | 2025.04.21 |
| 20250415 - spring 심화 1일차 (0) | 2025.04.15 |
| TIL - Schedule Develop 트러블 슈팅 (0) | 2025.04.04 |
| TIL - Bean Validation, EnableJpaAuditing (0) | 2025.04.02 |