Proxy and Associations

0ne·2024년 7월 4일

JPA

목록 보기
3/3

When and Why?

연관관계에 걸린 두 엔티티의 모든 정보를 조회해야하는 경우가 있는가 하면, 두 엔티티 중 하나의 정보만 조회해도 되는 경우도 있다.

프록시란?

em.getReference() : DB 쿼리가 안나가는데 객체가 조회가 되는 것.

  • em.find()는 DB를 조회해서 실제 entity 객체를 조회하는 반면, hibernate가 내부의 라이브러리를 이용해 가짜 엔티티객체 (프록시)를 줌
  • proxy : 1) 실제 클래스를 상속받아 만들어 겉 모양이 같음 2) 실제 객체의 reference(=target)을 보관함

프록시 특징

  1. proxy object는 처음 사용할 때 한 번만 초기화
  2. 프록시 객체를 초기화 할 때 프록시 객체가 실제 엔티티로 바뀌는 게 아님. 접근 가능해지는 것이지 내부의 참조만 target으로 가지게 될 뿐
  3. 원본 entity를 상속받기에 타입 체크시 주의 : ==대신 instanceof사용
  4. Persistence Context에 찾는 entity가 이미 있으면 em.getReference를 호출해도 실제 entity를 반환
    1) 이미 1차캐시에 있는데 proxy로 반환해봐야 얻을 수 있는 이점이 없음
    2) 한 PersistenceContext에 존재하고 PK가 동일하면 동일성을 보장하기 위해서
  5. PersistenceContext의 도움을 받을 수 없는 준영속상태일 때 proxy를 초기화하면 문제 발생

즉시로딩과 지연로딩

	@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);
    //member.team은 프록시임
    Team team = member.getTeam();
	team.getName(); //실제 team을 사용하는 시점에 초기화; DB조회

실무에선, 모든 연관관계에 지연로딩만 사용해야 함

  • JPQL fetch조인이나 entity 그래프기능을 사용해야 함.
  • 즉시로딩을 사용하면 예상치 못한 SQL이 발생
  • 또한 JPQL에서 N+1 문제를 일으킴
    • 처음 query를 하나 날렸는데 그것 때문에 추가 query가 n개 나간다고 해서 N+1문제라고 한다.
ManyToOne``OneToOne은 기본이 즉시로딩이므로 Lazy로 설정해야 함.

persistence Cascade

WHEN AND WHY? 특정 entity를 persist할 때 연관된 entity도 함께 persist하고 싶을 때
특히, 어떤 entity가 단일 Entity에 완전히 종속적일 때; 다른 entity와 연관관계가 없을 경우

  • 예를 들어, 부모 Entity를 저장할 때 자식 entity도 함께 저장하는 경우

association mapping과 아무 관련이 없음. 그저 함께 Persist하는 편리함을 제공할 뿐

종류

  • ALL
  • Persist
  • Remove

orphan Object

부모 Entity와 association이 끊어진 자식 entity를 자동으로 삭제
orphanRemoval = true

참조하는 곳이 하나일 때만 사용해야 함. 특정 Entity가 개인 소유할 때 사용해야 함.

CascadeType.ALL, orphanRemoval=true

  • 두 옵션을 모두 활성화할 때, 부모entity를 통해 자식의 생명 주기를 관리할 수 있음
  • 스스로 생명주기를 관리하는 entity는 em.persist()em.remove()로 제거한다.

DDD(도메인 주도 설계)의 Aggregate Root개념을 구현할 때 유용.

profile
@Hanyang univ(seoul). CSE

0개의 댓글