[JPA 프로그래밍 - 기본편] 프록시와 연관관계 관리

지현·2022년 2월 8일
0

JPA

목록 보기
8/12

프록시

  • em.find(): 데이터베이스를 통해서 실제 엔티티 객체 조회
  • em.getReference() : 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회, DB에 쿼리가 나가지 않는데 객체가 조회 됨
  • getReference()를 호출하는 시점에는 DB에 쿼리를 내보내지 않음, 이 값이 실제 사용되는 시점에, DB에서 꺼내와야하는 시점에 쿼리를 내보냄

프록시 특징

  • 실제 클래스와 겉 모양이 같음 (껍데기는 똑같은데 안에가 빈 것)
  • 프록시 객체는 실제 객체의 참조(target)를 보관
  • 초기에는 target값이 null
  • 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출
Member member = em.getReference(Member.class, “id”); 
// 프록시 객체를 가져옴
member.getName();
// target의 값이 없으면, JPA가 영속성 컨텍스트에 초기화를 요청
// 영속성 컨텍스트가 DB를 조회하고, 실제 엔티티를 생성해서 줌
// target과 실제 엔티티를 연결후 getName() 값 가져옴
  • 프록시 객체는 처음 사용할 때 한 번만 초기화
  • 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님, 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능 > 교체되는 것이 아니라 프록시는 유지 되고 내부의 target에만 값이 채워짐
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환
  • 그 반대도 마찬가지 (찾는 프록시가 이미 있으면 em.find()를 호출해도 프록시 반환) > JPA는 한 트랜잭션 내에서 같은 객체에 대해서 같다고 보장해줌
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생

즉시 로딩과 지연 로딩

지연 로딩

  • Team 객체를 가지고 있는 Member 객체를 조회할 때, Team 객체를 사용하지 않아도 Team 객체를 함께 조회해야 하는지?
  • 지연 로딩 LAZY을 사용해서 프록시로 조회
  • @ManyToOne(fetch = FetchType.LAZY)
  • 지연 로딩을 사용하면 연관된 것을 프록시로 가져옴
Member member = em.find(Member.class, 1L);//Team은 프록시로 조회

Team team = member.getTeam(); //이때 쿼리가 나가지는 않음(프록시를 가져오기 때문에)
team.getName();
// 실제 team을 사용하는 시점에 DB 초기화(DB 쿼리 나감)
// 프록시를 가져와서 실제 어떤 메서드를 사용할 때 

즉시 로딩

  • Member와 Team을 자주 함께 사용한다면?
  • 즉시 로딩 EAGER를 사용해서 함께 조회
  • @ManyToOne(fetch = FetchType.EAGER)
Member member = em.find(Member.class, 1L);
//Member와 Team을 한번에 조회 (프록시 X)

주의점

  • 모든 연관관계에 지연 로딩을 사용해야 함 > 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
  • 즉시 로딩은 JPQL에서 N+1 문제를 일으킴
  • @ManyToOne, @OneToOne은 기본이 즉시 로딩 > LAZY로 설정
  • @OneToMany, @ManyToMany는 기본이 지연 로딩
  • 즉시 로딩 대신 fetch join이나 엔티티 그래프 기능을 사용하는것이 좋음

영속성 전이(CASCADE)

  • 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속상태로 만들고 싶을 때
  • 라이프 사이클이 유사할 때 사용 (Child와 Parent의 라이프 사이클이 유사할 때)
  • 단일소유자, 소유자가 하나일 때만 사용 (Child를 소유하는 것은 Parent 하나일 때만 가능, 다른 엔티티가 Child와 관련 있을 때는 사용하면 안됨. Child에서 다른 엔티티와 관련 있는건 상관 없음)
public class class Parent{

	...
    
	@OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
    // Parent를 persist 할 때 컬렉션 안에 있는 것들에도 다 persist를 날려주겠다!
	private List<Child> childList = new ArrayList<>();

    ...
    
}

옵션

  • ALL: 모두 적용
  • PERSIST: 영속 (저장)
  • REMOVE: 삭제

고아 객체

  • 고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
  • orphanRemoval = true 옵션
  • 참조하는 곳이 하나일 때 사용해야함
  • 특정 엔티티가 개인 소유할 때 사용
  • @OneToOne, @OneToMany만 가능


출처
[인프런] 자바 ORM 표준 JPA 프로그래밍 - 기본편

0개의 댓글

Powered by GraphCDN, the GraphQL CDN