BACKEND/Spring

자바 ORM 표준 JPA 프로그래밍 - 기본편 섹션08

도라프 2022. 11. 14. 21:59

프록시

프록시는 왜 사용해야할까?

멤버를 조회할 때 team도 함께 조회를 해야할까? 라는 질문을 던져보자. 이건 비지니스 로직에 따라 달라진다.

 

만약 비지니스 로직에서 멤버와 팀을 같이 출력한다면, 멤버의 팀 정보를 불러온 다음에 연관된 팀도 가져오게 된다.

만일 멤버만 출력한다면, member.get만 챙겨오면 된다. 이럴 때 연관관계가 있다고 팀까지 가져오면 손해이다.

 

이런 경우에는 어떻게 해야할까? 이것을 해결하려면 프록시를 정확하게 이해해야 한다.

프록시 기초

em.find() vs em.getReference()

em.find(): 데이터베이스를 통해서 실제엔티티 객체 조회

em.getReference():데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회

 

프록시 특징

실제클래스를 상속받아서 만들어진다.

실제클래스와 모양이 같다.

• (이론상으로) 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.

프록시 객체는 실제 객체의 참조(target)보관

프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출

프록시 객체 초기화

Member member = em.getReference(Member.class, “id1”); 
member.getName();

이와 관련해서는 더 공부를 해볼 예정이다.

즉시 로딩과 지연 로딩

처음에 나왔던 질문인, member를 조회할 때, Team도 함께 조회해야할까?

비지니스 로직이 멤버만 조회하는 경우가 많다면,

지연로딩 LAZY사용해서 프록시로 조회

@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와 Team을 자주 함께 사용한다면?

즉시로딩 EAGER사용해서 함께 조회

@Entity
public class Member {
	@Id
	@GeneratedValue
    private Long id;
    @Column(name = "USERNAME")
    private String name;
    @ManyToOne(fetch = FetchType.EAGER) //**
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

프록시와 즉시로딩 주의

가급적 지연로딩만 사용하기

즉시로딩을 적용하면 예상하지 못한 SQL발생할 수 있다.

즉시로딩은 JPQL에서 N+1 문제를 일으킨다.

@ManyToOne, @OneToOne기본이 즉시로딩이므로 LAZY로 지연로딩으로 변환해 주어야 한다.

@OneToMany, @ManyToMany기본이 지연로딩이다.

 

 

영속성전이 + 고아객체, 생명주기

CascadeType.ALL + orphanRemovel=true

스스로 생명주기를 관리하는 엔티티는 em.persist()영속화, em.remove()제거

옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 있음

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