프록시를 왜 사용할까?
상황을 먼저 살펴보자.
Member는 Team 소속이다 그렇다고 Member를 조회할때 Team의 모든 것을 조회하는 것이 효율적일까?
프록시는 Member를 조회했을때 Team을 바로 조회하는 것이 아닌 그 값이 필요할 때, 조회를 한다.
em.find 와 비슷하지만 다르다.
em.find()
: 데이터베이스를 통해 실제 엔티티 객체 조회em.getReference()
: 데이터 베이스 조회를 미루는 가짜(proxy) 엔티티 조회실제 클래스를 상속받아 만든다.
실제 클래스와 겉모습은 같다.
사용하는 입장에서는 진짜 객체인지 프록시인지 구분하지 않고 사용해도 된다.
프록시 객체는 실제 객체의 참조 를 보관한다.
프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
프록시 객체는 처음 사용할 때 한번만 초기화 한다.
프록시 객체를 초기화할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아니다.
초기화되면 프록시 객체를 통해 실제 엔티티에 '접근'이 가능하다.
프록시 객체는 원본 엔티티를 상속받기 때문에, 타입을 ==
으로 비교하면 안되고 instance of
를 사용한다.
영속성 컨텍스트에 찾는 엔티티가 존재하면, 실제 엔티티를 반환한다.
프록시를 사용해서 할 수 있는 것이 뭐가 있을까?
아니 프록시를 왜,어떻게 사용할까? 라고 하면 지연로딩을 사용하기 위해서 라고 얘기할 수 있을 것 같다.
=> 지연 로딩 LAZY를 사용해서 프록시로 조회한다.
@ManyToOne(fetch = Fetchtype.LAZY)
@JoinColumn(name="TEAM_ID")
private Team team;
이렇게 LAZY 로딩으로 사용하게 되면, 실제 team을 사용하는 시점에 초기화(DB 조회)가 된다.
반대로 Member와 Team을 자주 함께 사용할때는 이거를 사용하면 된다.
EAGER
를 사용하면 Member 조회시 Team도 항상 조회하게 된다.
하지만 EAGER를 사용하게 되면 예상치 못한 SQL이 사용되기 때문에 N+1 문제를 일으킨다.
그래서 그냥 가급적 지연 로딩만 사용하는 것이 좋다고 한다.
@OneToMany
, @ManyToMany
는 기본이 지연로딩이라 괜찮지만
@ManyToOne
,@OneToOne
은 기본이 즉시로딩이라 LAZY로 변환해서 사용해야 한다.
특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용한다.
@OneToMany(mapped="parent",cascade= CascadeType.PERSIST)
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제한다.
참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능
@OneToOne
,@OneToMany
일 때 사용한다.
@OneToMany(mapped="parent",cascade= CascadeType.ALL,orphanRemoval=true)
두 옵션 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
도메인 주도 설계의 Aggreate Root 개념? 을 구현할 때 유용하다고 한다.